aboutsummaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/classes/ElggAutoP.php309
-rw-r--r--engine/classes/ElggMenuBuilder.php8
-rw-r--r--engine/classes/ElggMenuItem.php2
-rw-r--r--engine/classes/ElggPlugin.php7
-rw-r--r--engine/classes/ElggPluginManifest.php2
-rw-r--r--engine/classes/ElggPluginManifestParser.php6
-rw-r--r--engine/classes/ElggVolatileMetadataCache.php3
-rw-r--r--engine/classes/ElggXMLElement.php115
-rw-r--r--engine/lib/admin.php6
-rw-r--r--engine/lib/configuration.php26
-rw-r--r--engine/lib/elgglib.php22
-rw-r--r--engine/lib/entities.php206
-rw-r--r--engine/lib/group.php1
-rw-r--r--engine/lib/navigation.php26
-rw-r--r--engine/lib/objects.php1
-rw-r--r--engine/lib/output.php88
-rw-r--r--engine/lib/plugins.php21
-rw-r--r--engine/lib/river.php48
-rw-r--r--engine/lib/sites.php1
-rw-r--r--engine/lib/upgrade.php55
-rw-r--r--engine/lib/users.php1
-rw-r--r--engine/lib/views.php145
-rw-r--r--engine/lib/xml.php38
-rw-r--r--engine/tests/api/output.php74
-rw-r--r--engine/tests/test_files/output/autop/block-a.exp.norun.html6
-rw-r--r--engine/tests/test_files/output/autop/block-a.in.norun.html9
-rw-r--r--engine/tests/test_files/output/autop/domdoc_exp.html46
-rw-r--r--engine/tests/test_files/output/autop/domdoc_in.html80
-rw-r--r--engine/tests/test_files/output/autop/typical-post.exp.html84
-rw-r--r--engine/tests/test_files/output/autop/typical-post.in.html89
-rw-r--r--engine/tests/test_files/output/autop/wp-welcome.exp.html22
-rw-r--r--engine/tests/test_files/output/autop/wp-welcome.in.html25
-rw-r--r--engine/tests/test_files/output/autop/wpautop-fails.exp.html31
-rw-r--r--engine/tests/test_files/output/autop/wpautop-fails.in.html41
-rw-r--r--engine/tests/test_files/output/autop/wysiwyg-test.exp.html51
-rw-r--r--engine/tests/test_files/output/autop/wysiwyg-test.in.html79
36 files changed, 1496 insertions, 278 deletions
diff --git a/engine/classes/ElggAutoP.php b/engine/classes/ElggAutoP.php
new file mode 100644
index 000000000..89d77e583
--- /dev/null
+++ b/engine/classes/ElggAutoP.php
@@ -0,0 +1,309 @@
+<?php
+
+/**
+ * Create wrapper P and BR elements in HTML depending on newlines. Useful when
+ * users use newlines to signal line and paragraph breaks. In all cases output
+ * should be well-formed markup.
+ *
+ * In DIV elements, Ps are only added when there would be at
+ * least two of them.
+ */
+class ElggAutoP {
+
+ public $encoding = 'UTF-8';
+
+ /**
+ * @var DOMDocument
+ */
+ protected $_doc = null;
+
+ /**
+ * @var DOMXPath
+ */
+ protected $_xpath = null;
+
+ protected $_blocks = 'address article area aside blockquote caption col colgroup dd
+ details div dl dt fieldset figure figcaption footer form h1 h2 h3 h4 h5 h6 header
+ hr hgroup legend map math menu nav noscript p pre section select style summary
+ table tbody td tfoot th thead tr ul ol option li';
+
+ /**
+ * @var array
+ */
+ protected $_inlines = 'a abbr audio b button canvas caption cite code command datalist
+ del dfn em embed i iframe img input ins kbd keygen label map mark meter object
+ output progress q rp rt ruby s samp script select small source span strong style
+ sub sup textarea time var video wbr';
+
+ /**
+ * Descend into these elements to add Ps
+ *
+ * @var array
+ */
+ protected $_descendList = 'article aside blockquote body details div footer form
+ header section';
+
+ /**
+ * Add Ps inside these elements
+ *
+ * @var array
+ */
+ protected $_alterList = 'article aside blockquote body details div footer header
+ section';
+
+ protected $_unique = '';
+
+ public function __construct() {
+ $this->_blocks = preg_split('@\\s+@', $this->_blocks);
+ $this->_descendList = preg_split('@\\s+@', $this->_descendList);
+ $this->_alterList = preg_split('@\\s+@', $this->_alterList);
+ $this->_inlines = preg_split('@\\s+@', $this->_inlines);
+ $this->_unique = md5(__FILE__);
+ }
+
+ /**
+ * Intance of class for singleton pattern.
+ * @var ElggAutoP
+ */
+ private static $instance;
+
+ /**
+ * Singleton pattern.
+ * @return ElggAutoP
+ */
+ public static function getInstance() {
+ $className = __CLASS__;
+ if (!(self::$instance instanceof $className)) {
+ self::$instance = new $className();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Create wrapper P and BR elements in HTML depending on newlines. Useful when
+ * users use newlines to signal line and paragraph breaks. In all cases output
+ * should be well-formed markup.
+ *
+ * In DIV, LI, TD, and TH elements, Ps are only added when their would be at
+ * least two of them.
+ *
+ * @param string $html snippet
+ * @return string|false output or false if parse error occurred
+ */
+ public function process($html) {
+ // normalize whitespace
+ $html = str_replace(array("\r\n", "\r"), "\n", $html);
+
+ // allows preserving entities untouched
+ $html = str_replace('&', $this->_unique . 'AMP', $html);
+
+ $this->_doc = new DOMDocument();
+
+ // parse to DOM, suppressing loadHTML warnings
+ // http://www.php.net/manual/en/domdocument.loadhtml.php#95463
+ libxml_use_internal_errors(true);
+
+ if (!$this->_doc->loadHTML("<html><meta http-equiv='content-type' "
+ . "content='text/html; charset={$this->encoding}'><body>{$html}</body>"
+ . "</html>")) {
+ return false;
+ }
+
+ $this->_xpath = new DOMXPath($this->_doc);
+ // start processing recursively at the BODY element
+ $nodeList = $this->_xpath->query('//body[1]');
+ $this->_addParagraphs($nodeList->item(0));
+
+ // serialize back to HTML
+ $html = $this->_doc->saveHTML();
+
+ // split AUTOPs into multiples at /\n\n+/
+ $html = preg_replace('/(' . $this->_unique . 'NL){2,}/', '</autop><autop>', $html);
+ $html = str_replace(array($this->_unique . 'BR', $this->_unique . 'NL', '<br>'),
+ '<br />',
+ $html);
+ $html = str_replace('<br /></autop>', '</autop>', $html);
+
+ // re-parse so we can handle new AUTOP elements
+
+ if (!$this->_doc->loadHTML($html)) {
+ return false;
+ }
+ // must re-create XPath object after DOM load
+ $this->_xpath = new DOMXPath($this->_doc);
+
+ // strip AUTOPs that only have comments/whitespace
+ foreach ($this->_xpath->query('//autop') as $autop) {
+ $hasContent = false;
+ if (trim($autop->textContent) !== '') {
+ $hasContent = true;
+ } else {
+ foreach ($autop->childNodes as $node) {
+ if ($node->nodeType === XML_ELEMENT_NODE) {
+ $hasContent = true;
+ break;
+ }
+ }
+ }
+ if (!$hasContent) {
+ // strip w/ preg_replace later (faster than moving nodes out)
+ $autop->setAttribute("r", "1");
+ }
+ }
+
+ // remove a single AUTOP inside certain elements
+ foreach ($this->_xpath->query('//div') as $el) {
+ $autops = $this->_xpath->query('./autop', $el);
+ if ($autops->length === 1) {
+ // strip w/ preg_replace later (faster than moving nodes out)
+ $autops->item(0)->setAttribute("r", "1");
+ }
+ }
+
+ $html = $this->_doc->saveHTML();
+
+ // trim to the contents of BODY
+ $bodyStart = strpos($html, '<body>');
+ $bodyEnd = strpos($html, '</body>', $bodyStart + 6);
+ $html = substr($html, $bodyStart + 6, $bodyEnd - $bodyStart - 6);
+
+ // strip AUTOPs that should be removed
+ $html = preg_replace('@<autop r="1">(.*?)</autop>@', '\\1', $html);
+
+ // commit to converting AUTOPs to Ps
+ $html = str_replace('<autop>', "\n<p>", $html);
+ $html = str_replace('</autop>', "</p>\n", $html);
+
+ $html = str_replace('<br>', '<br />', $html);
+ $html = str_replace($this->_unique . 'AMP', '&', $html);
+ return $html;
+ }
+
+ /**
+ * Add P and BR elements as necessary
+ *
+ * @param DOMElement $el
+ */
+ protected function _addParagraphs(DOMElement $el) {
+ // no need to recurse, just queue up
+ $elsToProcess = array($el);
+ $inlinesToProcess = array();
+ while ($el = array_shift($elsToProcess)) {
+ // if true, we can alter all child nodes, if not, we'll just call
+ // _addParagraphs on each element in the descendInto list
+ $alterInline = in_array($el->nodeName, $this->_alterList);
+
+ // inside affected elements, we want to trim leading whitespace from
+ // the first text node
+ $ltrimFirstTextNode = true;
+
+ // should we open a new AUTOP element to move inline elements into?
+ $openP = true;
+ $autop = null;
+
+ // after BR, ignore a newline
+ $isFollowingBr = false;
+
+ $node = $el->firstChild;
+ while (null !== $node) {
+ if ($alterInline) {
+ if ($openP) {
+ $openP = false;
+ // create a P to move inline content into (this may be removed later)
+ $autop = $el->insertBefore($this->_doc->createElement('autop'), $node);
+ }
+ }
+
+ $isElement = ($node->nodeType === XML_ELEMENT_NODE);
+ if ($isElement) {
+ $elName = $node->nodeName;
+ }
+ $isBlock = ($isElement && in_array($elName, $this->_blocks));
+
+ if ($alterInline) {
+ $isInline = $isElement && ! $isBlock;
+ $isText = ($node->nodeType === XML_TEXT_NODE);
+ $isLastInline = (! $node->nextSibling
+ || ($node->nextSibling->nodeType === XML_ELEMENT_NODE
+ && in_array($node->nextSibling->nodeName, $this->_blocks)));
+ if ($isElement) {
+ $isFollowingBr = ($node->nodeName === 'br');
+ }
+
+ if ($isText) {
+ $nodeText = $node->nodeValue;
+ if ($ltrimFirstTextNode) {
+ $nodeText = ltrim($nodeText);
+ $ltrimFirstTextNode = false;
+ }
+ if ($isFollowingBr && preg_match('@^[ \\t]*\\n[ \\t]*@', $nodeText, $m)) {
+ // if a user ends a line with <br>, don't add a second BR
+ $nodeText = substr($nodeText, strlen($m[0]));
+ }
+ if ($isLastInline) {
+ $nodeText = rtrim($nodeText);
+ }
+ $nodeText = str_replace("\n", $this->_unique . 'NL', $nodeText);
+ $tmpNode = $node;
+ $node = $node->nextSibling; // move loop to next node
+
+ // alter node in place, then move into AUTOP
+ $tmpNode->nodeValue = $nodeText;
+ $autop->appendChild($tmpNode);
+
+ continue;
+ }
+ }
+ if ($isBlock || ! $node->nextSibling) {
+ if ($isBlock) {
+ if (in_array($node->nodeName, $this->_descendList)) {
+ $elsToProcess[] = $node;
+ //$this->_addParagraphs($node);
+ }
+ }
+ $openP = true;
+ $ltrimFirstTextNode = true;
+ }
+ if ($alterInline) {
+ if (! $isBlock) {
+ $tmpNode = $node;
+ if ($isElement && false !== strpos($tmpNode->textContent, "\n")) {
+ $inlinesToProcess[] = $tmpNode;
+ }
+ $node = $node->nextSibling;
+ $autop->appendChild($tmpNode);
+ continue;
+ }
+ }
+
+ $node = $node->nextSibling;
+ }
+ }
+
+ // handle inline nodes
+ // no need to recurse, just queue up
+ while ($el = array_shift($inlinesToProcess)) {
+ $ignoreLeadingNewline = false;
+ foreach ($el->childNodes as $node) {
+ if ($node->nodeType === XML_ELEMENT_NODE) {
+ if ($node->nodeValue === 'BR') {
+ $ignoreLeadingNewline = true;
+ } else {
+ $ignoreLeadingNewline = false;
+ if (false !== strpos($node->textContent, "\n")) {
+ $inlinesToProcess[] = $node;
+ }
+ }
+ continue;
+ } elseif ($node->nodeType === XML_TEXT_NODE) {
+ $text = $node->nodeValue;
+ if ($text[0] === "\n" && $ignoreLeadingNewline) {
+ $text = substr($text, 1);
+ $ignoreLeadingNewline = false;
+ }
+ $node->nodeValue = str_replace("\n", $this->_unique . 'BR', $text);
+ }
+ }
+ }
+ }
+}
diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php
index df0f9147f..d7f85685c 100644
--- a/engine/classes/ElggMenuBuilder.php
+++ b/engine/classes/ElggMenuBuilder.php
@@ -205,7 +205,7 @@ class ElggMenuBuilder {
// sort each section
foreach ($this->menu as $index => $section) {
foreach ($section as $key => $node) {
- $section[$key]->original_order = $key;
+ $section[$key]->setData('original_order', $key);
}
usort($section, $sort_callback);
$this->menu[$index] = $section;
@@ -240,7 +240,7 @@ class ElggMenuBuilder {
$result = strnatcmp($at, $bt);
if ($result === 0) {
- return $a->original_order - $b->original_order;
+ return $a->getData('original_order') - $b->getData('original_order');
}
return $result;
}
@@ -258,7 +258,7 @@ class ElggMenuBuilder {
$result = strcmp($an, $bn);
if ($result === 0) {
- return $a->original_order - $b->original_order;
+ return $a->getData('original_order') - $b->getData('original_order');
}
return $result;
}
@@ -275,7 +275,7 @@ class ElggMenuBuilder {
$bw = $b->getWeight();
if ($aw == $bw) {
- return $a->original_order - $b->original_order;
+ return $a->getData('original_order') - $b->getData('original_order');
}
return $aw - $bw;
}
diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php
index fe25f3ddd..81ce6c099 100644
--- a/engine/classes/ElggMenuItem.php
+++ b/engine/classes/ElggMenuItem.php
@@ -543,7 +543,7 @@ class ElggMenuItem {
*/
public function sortChildren($sortFunction) {
foreach ($this->data['children'] as $key => $node) {
- $this->data['children'][$key]->original_order = $key;
+ $this->data['children'][$key]->data['original_order'] = $key;
}
usort($this->data['children'], $sortFunction);
}
diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php
index 33f14ae37..32b5f952a 100644
--- a/engine/classes/ElggPlugin.php
+++ b/engine/classes/ElggPlugin.php
@@ -36,8 +36,9 @@ class ElggPlugin extends ElggObject {
* @warning Unlike other ElggEntity objects, you cannot null instantiate
* ElggPlugin. You must point it to an actual plugin GUID or location.
*
- * @param mixed $plugin The GUID of the ElggPlugin object or the path of
- * the plugin to load.
+ * @param mixed $plugin The GUID of the ElggPlugin object or the path of the plugin to load.
+ *
+ * @throws PluginException
*/
public function __construct($plugin) {
if (!$plugin) {
@@ -76,6 +77,8 @@ class ElggPlugin extends ElggObject {
// load the rest of the plugin
parent::__construct($existing_guid);
}
+
+ _elgg_cache_plugin_by_id($this);
}
/**
diff --git a/engine/classes/ElggPluginManifest.php b/engine/classes/ElggPluginManifest.php
index a4f5bb95d..6912c2b08 100644
--- a/engine/classes/ElggPluginManifest.php
+++ b/engine/classes/ElggPluginManifest.php
@@ -130,7 +130,7 @@ class ElggPluginManifest {
}
// see if we need to construct the xml object.
- if ($manifest instanceof XmlElement) {
+ if ($manifest instanceof ElggXMLElement) {
$manifest_obj = $manifest;
} else {
if (substr(trim($manifest), 0, 1) == '<') {
diff --git a/engine/classes/ElggPluginManifestParser.php b/engine/classes/ElggPluginManifestParser.php
index b0480d4d8..af152b561 100644
--- a/engine/classes/ElggPluginManifestParser.php
+++ b/engine/classes/ElggPluginManifestParser.php
@@ -53,10 +53,10 @@ abstract class ElggPluginManifestParser {
/**
* Loads the manifest XML to be parsed.
*
- * @param XmlElement $xml The Manifest XML object to be parsed
- * @param object $caller The object calling this parser.
+ * @param ElggXmlElement $xml The Manifest XML object to be parsed
+ * @param object $caller The object calling this parser.
*/
- public function __construct(XmlElement $xml, $caller) {
+ public function __construct(ElggXMLElement $xml, $caller) {
$this->manifestObject = $xml;
$this->caller = $caller;
}
diff --git a/engine/classes/ElggVolatileMetadataCache.php b/engine/classes/ElggVolatileMetadataCache.php
index 24ae58d42..8a33c198d 100644
--- a/engine/classes/ElggVolatileMetadataCache.php
+++ b/engine/classes/ElggVolatileMetadataCache.php
@@ -279,6 +279,9 @@ class ElggVolatileMetadataCache {
),
'selects' => array('n.string AS name', 'v.string AS value'),
'order_by' => 'n_table.entity_guid, n_table.time_created ASC',
+
+ // @todo don't know why this is necessary
+ 'wheres' => array(get_access_sql_suffix('n_table')),
);
$data = elgg_get_metadata($options);
diff --git a/engine/classes/ElggXMLElement.php b/engine/classes/ElggXMLElement.php
new file mode 100644
index 000000000..65a13912c
--- /dev/null
+++ b/engine/classes/ElggXMLElement.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * A parser for XML that uses SimpleXMLElement
+ *
+ * @package Elgg.Core
+ * @subpackage XML
+ */
+class ElggXMLElement {
+ /**
+ * @var SimpleXMLElement
+ */
+ private $_element;
+
+ /**
+ * Creates an ElggXMLParser from a string or existing SimpleXMLElement
+ *
+ * @param string|SimpleXMLElement $xml The XML to parse
+ */
+ public function __construct($xml) {
+ if ($xml instanceof SimpleXMLElement) {
+ $this->_element = $xml;
+ } else {
+ $this->_element = new SimpleXMLElement($xml);
+ }
+ }
+
+ /**
+ * @return string The name of the element
+ */
+ public function getName() {
+ return $this->_element->getName();
+ }
+
+ /**
+ * @return array:string The attributes
+ */
+ public function getAttributes() {
+ //include namespace declarations as attributes
+ $xmlnsRaw = $this->_element->getNamespaces();
+ $xmlns = array();
+ foreach ($xmlnsRaw as $key => $val) {
+ $label = 'xmlns' . ($key ? ":$key" : $key);
+ $xmlns[$label] = $val;
+ }
+ //get attributes and merge with namespaces
+ $attrRaw = $this->_element->attributes();
+ $attr = array();
+ foreach ($attrRaw as $key => $val) {
+ $attr[$key] = $val;
+ }
+ $attr = array_merge((array) $xmlns, (array) $attr);
+ $result = array();
+ foreach ($attr as $key => $val) {
+ $result[$key] = (string) $val;
+ }
+ return $result;
+ }
+
+ /**
+ * @return string CData
+ */
+ public function getContent() {
+ return (string) $this->_element;
+ }
+
+ /**
+ * @return array:ElggXMLElement Child elements
+ */
+ public function getChildren() {
+ $children = $this->_element->children();
+ $result = array();
+ foreach ($children as $val) {
+ $result[] = new ElggXMLElement($val);
+ }
+
+ return $result;
+ }
+
+ function __get($name) {
+ switch ($name) {
+ case 'name':
+ return $this->getName();
+ break;
+ case 'attributes':
+ return $this->getAttributes();
+ break;
+ case 'content':
+ return $this->getContent();
+ break;
+ case 'children':
+ return $this->getChildren();
+ break;
+ }
+ return null;
+ }
+
+ function __isset($name) {
+ switch ($name) {
+ case 'name':
+ return $this->getName() !== null;
+ break;
+ case 'attributes':
+ return $this->getAttributes() !== null;
+ break;
+ case 'content':
+ return $this->getContent() !== null;
+ break;
+ case 'children':
+ return $this->getChildren() !== null;
+ break;
+ }
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/engine/lib/admin.php b/engine/lib/admin.php
index b65d98c95..cb9524f11 100644
--- a/engine/lib/admin.php
+++ b/engine/lib/admin.php
@@ -233,6 +233,7 @@ function admin_init() {
elgg_register_action('admin/site/update_basic', '', 'admin');
elgg_register_action('admin/site/update_advanced', '', 'admin');
elgg_register_action('admin/site/flush_cache', '', 'admin');
+ elgg_register_action('admin/site/unlock_upgrade', '', 'admin');
elgg_register_action('admin/menu/save', '', 'admin');
@@ -268,8 +269,9 @@ function admin_init() {
// users
elgg_register_admin_menu_item('administer', 'users', null, 20);
elgg_register_admin_menu_item('administer', 'online', 'users', 10);
- elgg_register_admin_menu_item('administer', 'newest', 'users', 20);
- elgg_register_admin_menu_item('administer', 'add', 'users', 30);
+ elgg_register_admin_menu_item('administer', 'admins', 'users', 20);
+ elgg_register_admin_menu_item('administer', 'newest', 'users', 30);
+ elgg_register_admin_menu_item('administer', 'add', 'users', 40);
// configure
// plugins
diff --git a/engine/lib/configuration.php b/engine/lib/configuration.php
index 305aa00b6..b10e51130 100644
--- a/engine/lib/configuration.php
+++ b/engine/lib/configuration.php
@@ -91,23 +91,29 @@ function elgg_get_config($name, $site_guid = 0) {
return $CONFIG->$name;
}
- if ($site_guid === NULL) {
+ if ($site_guid === null) {
// installation wide setting
$value = datalist_get($name);
} else {
- // site specific setting
- if ($site_guid == 0) {
- $site_guid = (int) $CONFIG->site_id;
+ // hit DB only if we're not sure if value exists or not
+ if (!isset($CONFIG->site_config_loaded)) {
+ // site specific setting
+ if ($site_guid == 0) {
+ $site_guid = (int) $CONFIG->site_id;
+ }
+ $value = get_config($name, $site_guid);
+ } else {
+ $value = null;
}
- $value = get_config($name, $site_guid);
}
- if ($value !== false) {
- $CONFIG->$name = $value;
- return $value;
+ // @todo document why we don't cache false
+ if ($value === false) {
+ return null;
}
- return null;
+ $CONFIG->$name = $value;
+ return $value;
}
/**
@@ -558,6 +564,8 @@ function _elgg_load_site_config() {
$CONFIG->url = $CONFIG->wwwroot;
get_all_config();
+ // gives hint to elgg_get_config function how to approach missing values
+ $CONFIG->site_config_loaded = true;
}
/**
diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index dd3cba25d..540605876 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -710,9 +710,12 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority
*/
function elgg_unregister_event_handler($event, $object_type, $callback) {
global $CONFIG;
- foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) {
- if ($event_callback == $callback) {
- unset($CONFIG->events[$event][$object_type][$key]);
+
+ if (isset($CONFIG->events[$event]) && isset($CONFIG->events[$event][$object_type])) {
+ foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) {
+ if ($event_callback == $callback) {
+ unset($CONFIG->events[$event][$object_type][$key]);
+ }
}
}
}
@@ -889,9 +892,12 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority =
*/
function elgg_unregister_plugin_hook_handler($hook, $entity_type, $callback) {
global $CONFIG;
- foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) {
- if ($hook_callback == $callback) {
- unset($CONFIG->hooks[$hook][$entity_type][$key]);
+
+ if (isset($CONFIG->hooks[$hook]) && isset($CONFIG->hooks[$hook][$entity_type])) {
+ foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) {
+ if ($hook_callback == $callback) {
+ unset($CONFIG->hooks[$hook][$entity_type][$key]);
+ }
}
}
}
@@ -1073,8 +1079,8 @@ function _elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
case E_USER_WARNING :
case E_RECOVERABLE_ERROR: // (e.g. type hint violation)
- // check if the error wasn't suppressed by @-functionname
- if(error_reporting()){
+ // check if the error wasn't suppressed by the error control operator (@)
+ if (error_reporting()) {
error_log("PHP WARNING: $error");
}
break;
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 70a950b16..ce736ce05 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -17,13 +17,13 @@ global $ENTITY_CACHE;
$ENTITY_CACHE = array();
/**
- * Cache subtypes and related class names once loaded.
+ * Cache subtypes and related class names.
*
- * @global array $SUBTYPE_CACHE
+ * @global array|null $SUBTYPE_CACHE array once populated from DB, initially null
* @access private
*/
global $SUBTYPE_CACHE;
-$SUBTYPE_CACHE = NULL;
+$SUBTYPE_CACHE = null;
/**
* Invalidate this class's entry in the cache.
@@ -59,16 +59,24 @@ function invalidate_cache_for_entity($guid) {
function cache_entity(ElggEntity $entity) {
global $ENTITY_CACHE;
- // Don't cache entities while access control is off, otherwise they could be
+ // Don't cache non-plugin entities while access control is off, otherwise they could be
// exposed to users who shouldn't see them when control is re-enabled.
- if (elgg_get_ignore_access()) {
+ if (!($entity instanceof ElggPlugin) && elgg_get_ignore_access()) {
return;
}
// Don't store too many or we'll have memory problems
// TODO(evan): Pick a less arbitrary limit
if (count($ENTITY_CACHE) > 256) {
- unset($ENTITY_CACHE[array_rand($ENTITY_CACHE)]);
+ $random_guid = array_rand($ENTITY_CACHE);
+
+ unset($ENTITY_CACHE[$random_guid]);
+
+ // Purge separate metadata cache. Original idea was to do in entity destructor, but that would
+ // have caused a bunch of unnecessary purges at every shutdown. Doing it this way we have no way
+ // to know that the expunged entity will be GCed (might be another reference living), but that's
+ // OK; the metadata will reload if necessary.
+ elgg_get_metadata_cache()->clear($random_guid);
}
$ENTITY_CACHE[$entity->guid] = $entity;
@@ -87,8 +95,6 @@ function cache_entity(ElggEntity $entity) {
function retrieve_cached_entity($guid) {
global $ENTITY_CACHE;
- $guid = (int)$guid;
-
if (isset($ENTITY_CACHE[$guid])) {
if ($ENTITY_CACHE[$guid]->isFullyLoaded()) {
return $ENTITY_CACHE[$guid];
@@ -148,29 +154,23 @@ function retrieve_cached_entity_row($guid) {
* @access private
*/
function get_subtype_id($type, $subtype) {
- global $CONFIG, $SUBTYPE_CACHE;
+ global $SUBTYPE_CACHE;
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
-
- if ($subtype == "") {
- return FALSE;
+ if (!$subtype) {
+ return false;
}
- // @todo use the cache before hitting database
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes
- where type='$type' and subtype='$subtype'");
-
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
- $SUBTYPE_CACHE[$result->id] = $result;
+ // use the cache before hitting database
+ $result = _elgg_retrieve_cached_subtype($type, $subtype);
+ if ($result !== null) {
return $result->id;
}
- return FALSE;
+ return false;
}
/**
@@ -178,35 +178,67 @@ function get_subtype_id($type, $subtype) {
*
* @param int $subtype_id Subtype ID
*
- * @return string Subtype name
+ * @return string|false Subtype name, false if subtype not found
* @link http://docs.elgg.org/DataModel/Entities/Subtypes
* @see get_subtype_from_id()
* @access private
*/
function get_subtype_from_id($subtype_id) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $subtype_id = (int)$subtype_id;
+ global $SUBTYPE_CACHE;
if (!$subtype_id) {
return false;
}
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
if (isset($SUBTYPE_CACHE[$subtype_id])) {
return $SUBTYPE_CACHE[$subtype_id]->subtype;
}
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id");
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
+ return false;
+}
+
+/**
+ * Retrieve subtype from the cache.
+ *
+ * @param string $type
+ * @param string $subtype
+ * @return stdClass|null
+ *
+ * @access private
+ */
+function _elgg_retrieve_cached_subtype($type, $subtype) {
+ global $SUBTYPE_CACHE;
- $SUBTYPE_CACHE[$subtype_id] = $result;
- return $result->subtype;
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
}
- return false;
+ foreach ($SUBTYPE_CACHE as $obj) {
+ if ($obj->type === $type && $obj->subtype === $subtype) {
+ return $obj;
+ }
+ }
+ return null;
+}
+
+/**
+ * Fetch all suptypes from DB to local cache.
+ *
+ * @access private
+ */
+function _elgg_populate_subtype_cache() {
+ global $CONFIG, $SUBTYPE_CACHE;
+
+ $results = get_data("SELECT * FROM {$CONFIG->dbprefix}entity_subtypes");
+
+ $SUBTYPE_CACHE = array();
+ foreach ($results as $row) {
+ $SUBTYPE_CACHE[$row->id] = $row;
+ }
}
/**
@@ -225,25 +257,19 @@ function get_subtype_from_id($subtype_id) {
* @access private
*/
function get_subtype_class($type, $subtype) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
-
- // @todo use the cache before going to the database
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes
- where type='$type' and subtype='$subtype'");
+ global $SUBTYPE_CACHE;
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
-
- $SUBTYPE_CACHE[$result->id] = $result;
- return $result->class;
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
+ // use the cache before going to the database
+ $obj = _elgg_retrieve_cached_subtype($type, $subtype);
+ if ($obj) {
+ return $obj->class;
}
- return NULL;
+ return null;
}
/**
@@ -257,29 +283,21 @@ function get_subtype_class($type, $subtype) {
* @access private
*/
function get_subtype_class_from_id($subtype_id) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $subtype_id = (int)$subtype_id;
+ global $SUBTYPE_CACHE;
if (!$subtype_id) {
- return false;
+ return null;
}
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
if (isset($SUBTYPE_CACHE[$subtype_id])) {
return $SUBTYPE_CACHE[$subtype_id]->class;
}
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id");
-
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
- $SUBTYPE_CACHE[$subtype_id] = $result;
- return $result->class;
- }
-
- return NULL;
+ return null;
}
/**
@@ -305,21 +323,32 @@ function get_subtype_class_from_id($subtype_id) {
* @see get_entity()
*/
function add_subtype($type, $subtype, $class = "") {
- global $CONFIG;
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
- $class = sanitise_string($class);
+ global $CONFIG, $SUBTYPE_CACHE;
- // Short circuit if no subtype is given
- if ($subtype == "") {
+ if (!$subtype) {
return 0;
}
$id = get_subtype_id($type, $subtype);
- if ($id == 0) {
- return insert_data("insert into {$CONFIG->dbprefix}entity_subtypes"
- . " (type, subtype, class) values ('$type','$subtype','$class')");
+ if (!$id) {
+ // In cache we store non-SQL-escaped strings because that's what's returned by query
+ $cache_obj = (object) array(
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'class' => $class,
+ );
+
+ $type = sanitise_string($type);
+ $subtype = sanitise_string($subtype);
+ $class = sanitise_string($class);
+
+ $id = insert_data("INSERT INTO {$CONFIG->dbprefix}entity_subtypes"
+ . " (type, subtype, class) VALUES ('$type', '$subtype', '$class')");
+
+ // add entry to cache
+ $cache_obj->id = $id;
+ $SUBTYPE_CACHE[$id] = $cache_obj;
}
return $id;
@@ -361,22 +390,31 @@ function remove_subtype($type, $subtype) {
function update_subtype($type, $subtype, $class = '') {
global $CONFIG, $SUBTYPE_CACHE;
- if (!$id = get_subtype_id($type, $subtype)) {
- return FALSE;
+ $id = get_subtype_id($type, $subtype);
+ if (!$id) {
+ return false;
}
+
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
+ $unescaped_class = $class;
+
$type = sanitise_string($type);
$subtype = sanitise_string($subtype);
-
- $result = update_data("UPDATE {$CONFIG->dbprefix}entity_subtypes
+ $class = sanitise_string($class);
+
+ $success = update_data("UPDATE {$CONFIG->dbprefix}entity_subtypes
SET type = '$type', subtype = '$subtype', class = '$class'
WHERE id = $id
");
- if ($result && isset($SUBTYPE_CACHE[$id])) {
- $SUBTYPE_CACHE[$id]->class = $class;
+ if ($success && isset($SUBTYPE_CACHE[$id])) {
+ $SUBTYPE_CACHE[$id]->class = $unescaped_class;
}
- return $result;
+ return $success;
}
/**
@@ -1874,7 +1912,7 @@ function oddentity_to_elggentity(ODDEntity $element) {
if (!$tmp) {
// Construct new class with owner from session
$classname = get_subtype_class($class, $subclass);
- if ($classname != "") {
+ if ($classname) {
if (class_exists($classname)) {
$tmp = new $classname();
diff --git a/engine/lib/group.php b/engine/lib/group.php
index feb1f1e7f..852c08de9 100644
--- a/engine/lib/group.php
+++ b/engine/lib/group.php
@@ -33,6 +33,7 @@ function get_group_entity_as_row($guid) {
* @param string $description Description
*
* @return bool
+ * @access private
*/
function create_group_entity($guid, $name, $description) {
global $CONFIG;
diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php
index 8c3952594..86624cd7c 100644
--- a/engine/lib/navigation.php
+++ b/engine/lib/navigation.php
@@ -308,6 +308,32 @@ function elgg_site_menu_setup($hook, $type, $return, $params) {
$return['more'] = array_splice($return['default'], $max_display_items);
}
}
+
+ // check if we have anything selected
+ $selected = false;
+ foreach ($return as $section_name => $section) {
+ foreach ($section as $key => $item) {
+ if ($item->getSelected()) {
+ $selected = true;
+ break 2;
+ }
+ }
+ }
+
+ if (!$selected) {
+ // nothing selected, match name to context
+ foreach ($return as $section_name => $section) {
+ foreach ($section as $key => $item) {
+ // only highlight internal links
+ if (strpos($item->getHref(), elgg_get_site_url()) === 0) {
+ if ($item->getName() == elgg_get_context()) {
+ $return[$section_name][$key]->setSelected(true);
+ break 2;
+ }
+ }
+ }
+ }
+ }
return $return;
}
diff --git a/engine/lib/objects.php b/engine/lib/objects.php
index f186c66cb..e5e8f67c4 100644
--- a/engine/lib/objects.php
+++ b/engine/lib/objects.php
@@ -31,6 +31,7 @@ function get_object_entity_as_row($guid) {
* @param string $description The object's description
*
* @return bool
+ * @access private
*/
function create_object_entity($guid, $title, $description) {
global $CONFIG;
diff --git a/engine/lib/output.php b/engine/lib/output.php
index 352de863b..bff0bf6e9 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -16,7 +16,7 @@
**/
function parse_urls($text) {
// @todo this causes problems with <attr = "val">
- // must be ing <attr="val"> format (no space).
+ // must be in <attr="val"> format (no space).
// By default htmlawed rewrites tags to this format.
// if PHP supported conditional negative lookbehinds we could use this:
// $r = preg_replace_callback('/(?<!=)(?<![ ])?(?<!["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\),]+)/i',
@@ -43,51 +43,26 @@ function parse_urls($text) {
/**
* Create paragraphs from text with line spacing
- * Borrowed from Wordpress.
*
* @param string $pee The string
- * @param bool $br Add BRs?
+ * @deprecated Use elgg_autop instead
+ * @todo Add deprecation warning in 1.9
*
- * @todo Rewrite
* @return string
**/
-function autop($pee, $br = 1) {
- $pee = $pee . "\n"; // just to make things a little easier, pad the end
- $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
- // Space things out a little
- $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)';
- $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
- $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
- $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
- if (strpos($pee, '<object') !== false) {
- $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
- $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
- }
- $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
- $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "<p>$1</p>\n", $pee); // make paragraphs, including one at the end
- $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
- $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee);
- $pee = preg_replace('|<p>|', "$1<p>", $pee);
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
- $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
- $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
- $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
- if ($br) {
- $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
- $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
- $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
- }
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
- $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
- //if (strpos($pee, '<pre') !== false) {
- // mind the space between the ? and >. Only there because of the comment.
- // $pee = preg_replace_callback('!(<pre.*? >)(.*?)</pre>!is', 'clean_pre', $pee );
- //}
- $pee = preg_replace("|\n</p>$|", '</p>', $pee);
-
- return $pee;
+function autop($pee) {
+ return elgg_autop($pee);
+}
+
+/**
+ * Create paragraphs from text with line spacing
+ *
+ * @param string $string The string
+ *
+ * @return string
+ **/
+function elgg_autop($string) {
+ return ElggAutoP::getInstance()->process($string);
}
/**
@@ -384,7 +359,7 @@ function elgg_get_friendly_time($time) {
/**
* Strip tags and offer plugins the chance.
* Plugins register for output:strip_tags plugin hook.
- * Original string included in $params['original_string']
+ * Original string included in $params['original_string']
*
* @param string $string Formatted string
*
@@ -440,3 +415,32 @@ function _elgg_html_decode($string) {
);
return $string;
}
+
+/**
+ * Unit tests for Output
+ *
+ * @param sting $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
+function output_unit_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/output.php';
+ return $value;
+}
+
+/**
+ * Initialise the Output subsystem.
+ *
+ * @return void
+ * @access private
+ */
+function output_init() {
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'output_unit_test');
+}
+
+elgg_register_event_handler('init', 'system', 'output_init');
diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php
index cc1b4b9c7..94aff277e 100644
--- a/engine/lib/plugins.php
+++ b/engine/lib/plugins.php
@@ -176,6 +176,19 @@ function elgg_generate_plugin_entities() {
}
/**
+ * Cache a reference to this plugin by its ID
+ *
+ * @param ElggPlugin $plugin
+ *
+ * @access private
+ */
+function _elgg_cache_plugin_by_id(ElggPlugin $plugin) {
+ $map = (array) elgg_get_config('plugins_by_id_map');
+ $map[$plugin->getID()] = $plugin;
+ elgg_set_config('plugins_by_id_map', $map);
+}
+
+/**
* Returns an ElggPlugin object with the path $path.
*
* @param string $plugin_id The id (dir name) of the plugin. NOT the guid.
@@ -183,6 +196,11 @@ function elgg_generate_plugin_entities() {
* @since 1.8.0
*/
function elgg_get_plugin_from_id($plugin_id) {
+ $map = (array) elgg_get_config('plugins_by_id_map');
+ if (isset($map[$plugin_id])) {
+ return $map[$plugin_id];
+ }
+
$plugin_id = sanitize_string($plugin_id);
$db_prefix = get_config('dbprefix');
@@ -513,6 +531,8 @@ function elgg_namespace_plugin_private_setting($type, $name, $id = null) {
* @return string|false Plugin name, or false if no plugin name was called
* @since 1.8.0
* @access private
+ *
+ * @todo get rid of this
*/
function elgg_get_calling_plugin_id($mainfilename = false) {
if (!$mainfilename) {
@@ -921,6 +941,7 @@ function elgg_set_plugin_setting($name, $value, $plugin_id = null) {
*
* @return mixed
* @since 1.8.0
+ * @todo make $plugin_id required in future version
*/
function elgg_get_plugin_setting($name, $plugin_id = null) {
if ($plugin_id) {
diff --git a/engine/lib/river.php b/engine/lib/river.php
index b717a7756..33f34360e 100644
--- a/engine/lib/river.php
+++ b/engine/lib/river.php
@@ -361,6 +361,7 @@ function elgg_get_river(array $options = array()) {
}
$river_items = get_data($query, 'elgg_row_to_elgg_river_item');
+ _elgg_prefetch_river_entities($river_items);
return $river_items;
} else {
@@ -370,11 +371,56 @@ function elgg_get_river(array $options = array()) {
}
/**
+ * Prefetch entities that will be displayed in the river.
+ *
+ * @param ElggRiverItem[] $river_items
+ * @access private
+ */
+function _elgg_prefetch_river_entities(array $river_items) {
+ // prefetch objects and subjects
+ $guids = array();
+ foreach ($river_items as $item) {
+ if ($item->subject_guid && !retrieve_cached_entity($item->subject_guid)) {
+ $guids[$item->subject_guid] = true;
+ }
+ if ($item->object_guid && !retrieve_cached_entity($item->object_guid)) {
+ $guids[$item->object_guid] = true;
+ }
+ }
+ if ($guids) {
+ // avoid creating oversized query
+ // @todo how to better handle this?
+ $guids = array_slice($guids, 0, 300, true);
+ // return value unneeded, just priming cache
+ elgg_get_entities(array(
+ 'guids' => array_keys($guids),
+ 'limit' => 0,
+ ));
+ }
+
+ // prefetch object containers
+ $guids = array();
+ foreach ($river_items as $item) {
+ $object = $item->getObjectEntity();
+ if ($object->container_guid && !retrieve_cached_entity($object->container_guid)) {
+ $guids[$object->container_guid] = true;
+ }
+ }
+ if ($guids) {
+ $guids = array_slice($guids, 0, 300, true);
+ elgg_get_entities(array(
+ 'guids' => array_keys($guids),
+ 'limit' => 0,
+ ));
+ }
+}
+
+/**
* List river items
*
* @param array $options Any options from elgg_get_river() plus:
* pagination => BOOL Display pagination links (true)
-
+ *
* @return string
* @since 1.8.0
*/
diff --git a/engine/lib/sites.php b/engine/lib/sites.php
index 8b772668d..d9eb2d25e 100644
--- a/engine/lib/sites.php
+++ b/engine/lib/sites.php
@@ -58,6 +58,7 @@ function get_site_entity_as_row($guid) {
* @param string $url URL of the site
*
* @return bool
+ * @access private
*/
function create_site_entity($guid, $name, $description, $url) {
global $CONFIG;
diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php
index f0874a483..f4f4b16f5 100644
--- a/engine/lib/upgrade.php
+++ b/engine/lib/upgrade.php
@@ -311,3 +311,58 @@ function elgg_upgrade_bootstrap_17_to_18() {
return elgg_set_processed_upgrades($processed_upgrades);
}
+
+/**
+ * Creates a table {prefix}upgrade_lock that is used as a mutex for upgrades.
+ *
+ * @see _elgg_upgrade_lock()
+ *
+ * @return bool
+ * @access private
+ */
+function _elgg_upgrade_lock() {
+ global $CONFIG;
+
+ if (!_elgg_upgrade_is_locked()) {
+ // lock it
+ insert_data("create table {$CONFIG->dbprefix}upgrade_lock (id INT)");
+ elgg_log('Locked for upgrade.', 'NOTICE');
+ return true;
+ }
+
+ elgg_log('Cannot lock for upgrade: already locked.', 'WARNING');
+ return false;
+}
+
+/**
+ * Unlocks upgrade.
+ *
+ * @see _elgg_upgrade_lock()
+ *
+ * @access private
+ */
+function _elgg_upgrade_unlock() {
+ global $CONFIG;
+ delete_data("drop table {$CONFIG->dbprefix}upgrade_lock");
+ elgg_log('Upgrade unlocked.', 'NOTICE');
+}
+
+/**
+ * Checks if upgrade is locked
+ *
+ * @return bool
+ * @access private
+ */
+function _elgg_upgrade_is_locked() {
+ global $CONFIG, $DB_QUERY_CACHE;
+
+ $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}upgrade_lock'"));
+
+ // Invalidate query cache
+ if ($DB_QUERY_CACHE) {
+ $DB_QUERY_CACHE->clear();
+ elgg_log("Query cache invalidated", 'NOTICE');
+ }
+
+ return $is_locked;
+}
diff --git a/engine/lib/users.php b/engine/lib/users.php
index 527eff3cd..95ef9d176 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -44,6 +44,7 @@ function get_user_entity_as_row($guid) {
* @param string $code A code
*
* @return bool
+ * @access private
*/
function create_user_entity($guid, $name, $username, $password, $salt, $email, $language, $code) {
global $CONFIG;
diff --git a/engine/lib/views.php b/engine/lib/views.php
index 8a0642c2b..69bceabf5 100644
--- a/engine/lib/views.php
+++ b/engine/lib/views.php
@@ -101,15 +101,15 @@ function elgg_get_viewtype() {
return $CURRENT_SYSTEM_VIEWTYPE;
}
- $viewtype = get_input('view', NULL);
- if ($viewtype) {
+ $viewtype = get_input('view', '', false);
+ if (is_string($viewtype) && $viewtype !== '') {
// only word characters allowed.
- if (!preg_match('[\W]', $viewtype)) {
+ if (!preg_match('/\W/', $viewtype)) {
return $viewtype;
}
}
- if (isset($CONFIG->view) && !empty($CONFIG->view)) {
+ if (!empty($CONFIG->view)) {
return $CONFIG->view;
}
@@ -258,8 +258,6 @@ function elgg_get_view_location($view, $viewtype = '') {
} else {
return $CONFIG->views->locations[$viewtype][$view];
}
-
- return false;
}
/**
@@ -329,7 +327,7 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
$location = $CONFIG->views->locations[$viewtype][$view];
}
- if (file_exists($location . "{$viewtype}/{$view}.php")) {
+ if (file_exists("{$location}{$viewtype}/{$view}.php")) {
return true;
}
@@ -378,7 +376,7 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
* @param boolean $bypass If set to true, elgg_view will bypass any specified
* alternative template handler; by default, it will
* hand off to this if requested (see set_template_handler)
- * @param boolean $debug If set to true, the viewer will complain if it can't find a view
+ * @param boolean $ignored This argument is ignored and will be removed eventually
* @param string $viewtype If set, forces the viewtype for the elgg_view call to be
* this value (default: standard detection)
*
@@ -386,18 +384,30 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
* @see set_template_handler()
* @example views/elgg_view.php
* @link http://docs.elgg.org/View
- * @todo $debug isn't used.
- * @todo $usercache is redundant.
*/
-function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $viewtype = '') {
+function elgg_view($view, $vars = array(), $bypass = false, $ignored = false, $viewtype = '') {
global $CONFIG;
- static $usercache;
-
- $view = (string)$view;
+ if (!is_string($view) || !is_string($viewtype)) {
+ elgg_log("View and Viewtype in views must be a strings: $view", 'NOTICE');
+ return '';
+ }
// basic checking for bad paths
if (strpos($view, '..') !== false) {
- return false;
+ return '';
+ }
+
+ if (!is_array($vars)) {
+ elgg_log("Vars in views must be an array: $view", 'ERROR');
+ $vars = array();
+ }
+
+ // Get the current viewtype
+ if ($viewtype === '') {
+ $viewtype = elgg_get_viewtype();
+ } elseif (preg_match('/\W/', $viewtype)) {
+ // Viewtypes can only be alphanumeric
+ return '';
}
$view_orig = $view;
@@ -408,19 +418,6 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
elgg_trigger_event('pagesetup', 'system');
}
- if (!is_array($usercache)) {
- $usercache = array();
- }
-
- if (!is_array($vars)) {
- elgg_log("Vars in views must be an array: $view", 'ERROR');
- $vars = array();
- }
-
- if (empty($vars)) {
- $vars = array();
- }
-
// @warning - plugin authors: do not expect user, config, and url to be
// set by elgg_view() in the future. Instead, use elgg_get_logged_in_user_entity(),
// elgg_get_config(), and elgg_get_site_url() in your views.
@@ -475,16 +472,6 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
}
}
- // Get the current viewtype
- if (empty($viewtype)) {
- $viewtype = elgg_get_viewtype();
- }
-
- // Viewtypes can only be alphanumeric
- if (preg_match('[\W]', $viewtype)) {
- return '';
- }
-
// Set up any extensions to the requested view
if (isset($CONFIG->views->extensions[$view])) {
$viewlist = $CONFIG->views->extensions[$view];
@@ -496,19 +483,21 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
ob_start();
foreach ($viewlist as $priority => $view) {
+
$view_location = elgg_get_view_location($view, $viewtype);
$view_file = "$view_location$viewtype/$view.php";
- $default_location = elgg_get_view_location($view, 'default');
- $default_view_file = "{$default_location}default/$view.php";
-
// try to include view
if (!file_exists($view_file) || !include($view_file)) {
// requested view does not exist
$error = "$viewtype/$view view does not exist.";
// attempt to load default view
- if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
+ if ($viewtype !== 'default' && elgg_does_viewtype_fallback($viewtype)) {
+
+ $default_location = elgg_get_view_location($view, 'default');
+ $default_view_file = "{$default_location}default/$view.php";
+
if (file_exists($default_view_file) && include($default_view_file)) {
// default view found
$error .= " Using default/$view instead.";
@@ -533,7 +522,7 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
// backward compatibility with less granular hook will be gone in 2.0
$content_tmp = elgg_trigger_plugin_hook('display', 'view', $params, $content);
- if ($content_tmp != $content) {
+ if ($content_tmp !== $content) {
$content = $content_tmp;
elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name', 1.8);
}
@@ -559,33 +548,32 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
* @param string $view_extension This view is added to $view
* @param int $priority The priority, from 0 to 1000,
* to add at (lowest numbers displayed first)
- * @param string $viewtype Not used
*
* @return void
* @since 1.7.0
* @link http://docs.elgg.org/Views/Extend
* @example views/extend.php
*/
-function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') {
+function elgg_extend_view($view, $view_extension, $priority = 501) {
global $CONFIG;
if (!isset($CONFIG->views)) {
- $CONFIG->views = new stdClass;
- }
-
- if (!isset($CONFIG->views->extensions)) {
- $CONFIG->views->extensions = array();
- }
-
- if (!isset($CONFIG->views->extensions[$view])) {
- $CONFIG->views->extensions[$view][500] = "{$view}";
+ $CONFIG->views = (object) array(
+ 'extensions' => array(),
+ );
+ $CONFIG->views->extensions[$view][500] = (string)$view;
+ } else {
+ if (!isset($CONFIG->views->extensions[$view])) {
+ $CONFIG->views->extensions[$view][500] = (string)$view;
+ }
}
+ // raise priority until it doesn't match one already registered
while (isset($CONFIG->views->extensions[$view][$priority])) {
$priority++;
}
- $CONFIG->views->extensions[$view][$priority] = "{$view_extension}";
+ $CONFIG->views->extensions[$view][$priority] = (string)$view_extension;
ksort($CONFIG->views->extensions[$view]);
}
@@ -601,14 +589,6 @@ function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '
function elgg_unextend_view($view, $view_extension) {
global $CONFIG;
- if (!isset($CONFIG->views)) {
- return FALSE;
- }
-
- if (!isset($CONFIG->views->extensions)) {
- return FALSE;
- }
-
if (!isset($CONFIG->views->extensions[$view])) {
return FALSE;
}
@@ -1105,10 +1085,6 @@ function elgg_view_annotation_list($annotations, array $vars = array()) {
* @todo Change the hook name.
*/
function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) {
- if (!$entity) {
- return false;
- }
-
if (!($entity instanceof ElggEntity)) {
return false;
}
@@ -1131,7 +1107,7 @@ function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) {
* This is a shortcut for {@elgg_view page/elements/title}.
*
* @param string $title The page title
- * @param string $vars View variables (was submenu be displayed? (deprecated))
+ * @param array $vars View variables (was submenu be displayed? (deprecated))
*
* @return string The HTML (etc)
*/
@@ -1203,7 +1179,7 @@ function elgg_view_comments($entity, $add_comment = true, array $vars = array())
*
* @param string $image The icon and other information
* @param string $body Description content
- * @param string $vars Additional parameters for the view
+ * @param array $vars Additional parameters for the view
*
* @return string
* @since 1.8.0
@@ -1230,7 +1206,6 @@ function elgg_view_image_block($image, $body, $vars = array()) {
* @since 1.8.0
*/
function elgg_view_module($type, $title, $body, array $vars = array()) {
-
$vars['class'] = elgg_extract('class', $vars, '') . " elgg-module-$type";
$vars['title'] = $title;
$vars['body'] = $body;
@@ -1243,11 +1218,15 @@ function elgg_view_module($type, $title, $body, array $vars = array()) {
* @param ElggRiverItem $item A river item object
* @param array $vars An array of variables for the view
*
- * @return string|false Depending on success
+ * @return string returns empty string if could not be rendered
*/
function elgg_view_river_item($item, array $vars = array()) {
+ if (!($item instanceof ElggRiverItem)) {
+ return '';
+ }
// checking default viewtype since some viewtypes do not have unique views per item (rss)
- if (!$item || !$item->getView() || !elgg_view_exists($item->getView(), 'default')) {
+ $view = $item->getView();
+ if (!$view || !elgg_view_exists($view, 'default')) {
return '';
}
@@ -1339,7 +1318,7 @@ function elgg_view_list_item($item, array $vars = array()) {
return elgg_view_river_item($item, $vars);
}
- return false;
+ return '';
}
/**
@@ -1354,7 +1333,7 @@ function elgg_view_list_item($item, array $vars = array()) {
*/
function elgg_view_icon($name, $class = '') {
// @todo deprecate boolean in Elgg 1.9
- if (is_bool($class) && $class === true) {
+ if ($class === true) {
$class = 'float';
}
return "<span class=\"elgg-icon elgg-icon-$name $class\"></span>";
@@ -1517,17 +1496,13 @@ function elgg_view_tree($view_root, $viewtype = "") {
* @param string $base_location_path The base views directory to use with elgg_set_view_location()
* @param string $viewtype The type of view we're looking at (default, rss, etc)
*
- * @return void
+ * @return bool returns false if folder can't be read
* @since 1.7.0
* @see elgg_set_view_location()
* @todo This seems overly complicated.
* @access private
*/
function autoregister_views($view_base, $folder, $base_location_path, $viewtype) {
- if (!isset($i)) {
- $i = 0;
- }
-
if ($handle = opendir($folder)) {
while ($view = readdir($handle)) {
if (!in_array($view, array('.', '..', '.svn', 'CVS')) && !is_dir($folder . "/" . $view)) {
@@ -1609,16 +1584,15 @@ function elgg_views_handle_deprecated_views() {
function elgg_views_boot() {
global $CONFIG;
- elgg_register_simplecache_view('css/elgg');
elgg_register_simplecache_view('css/ie');
elgg_register_simplecache_view('css/ie6');
elgg_register_simplecache_view('css/ie7');
- elgg_register_simplecache_view('js/elgg');
elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.4.min.js', 'head');
elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head');
elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js');
-
+
+ elgg_register_simplecache_view('js/elgg');
$elgg_js_url = elgg_get_simplecache_url('js', 'elgg');
elgg_register_js('elgg', $elgg_js_url, 'head');
@@ -1627,14 +1601,17 @@ function elgg_views_boot() {
elgg_load_js('elgg');
elgg_register_simplecache_view('js/lightbox');
- elgg_register_simplecache_view('css/lightbox');
$lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox');
elgg_register_js('lightbox', $lightbox_js_url);
+
+ elgg_register_simplecache_view('css/lightbox');
$lightbox_css_url = elgg_get_simplecache_url('css', 'lightbox');
elgg_register_css('lightbox', $lightbox_css_url);
+ elgg_register_simplecache_view('css/elgg');
$elgg_css_url = elgg_get_simplecache_url('css', 'elgg');
elgg_register_css('elgg', $elgg_css_url);
+
elgg_load_css('elgg');
elgg_register_ajax_view('js/languages');
@@ -1648,7 +1625,7 @@ function elgg_views_boot() {
$views = scandir($view_path);
foreach ($views as $view) {
- if ('.' !== substr($view, 0, 1) && is_dir($view_path . $view)) {
+ if ($view[0] !== '.' && is_dir($view_path . $view)) {
elgg_register_viewtype($view);
}
}
diff --git a/engine/lib/xml.php b/engine/lib/xml.php
index 813bc4ee0..ff82d7e8a 100644
--- a/engine/lib/xml.php
+++ b/engine/lib/xml.php
@@ -101,47 +101,11 @@ function serialise_array_to_xml(array $data, $n = 0) {
/**
* Parse an XML file into an object.
- * Based on code from http://de.php.net/manual/en/function.xml-parse-into-struct.php by
- * efredricksen at gmail dot com
*
* @param string $xml The XML
*
* @return object
*/
function xml_to_object($xml) {
- $parser = xml_parser_create();
-
- // Parse $xml into a structure
- xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
- xml_parse_into_struct($parser, $xml, $tags);
-
- xml_parser_free($parser);
-
- $elements = array();
- $stack = array();
-
- foreach ($tags as $tag) {
- $index = count($elements);
-
- if ($tag['type'] == "complete" || $tag['type'] == "open") {
- $elements[$index] = new XmlElement;
- $elements[$index]->name = $tag['tag'];
- $elements[$index]->attributes = elgg_extract('attributes', $tag, '');
- $elements[$index]->content = elgg_extract('value', $tag, '');
-
- if ($tag['type'] == "open") {
- $elements[$index]->children = array();
- $stack[count($stack)] = &$elements;
- $elements = &$elements[$index]->children;
- }
- }
-
- if ($tag['type'] == "close") {
- $elements = &$stack[count($stack) - 1];
- unset($stack[count($stack) - 1]);
- }
- }
-
- return $elements[0];
+ return new ElggXMLElement($xml);
}
diff --git a/engine/tests/api/output.php b/engine/tests/api/output.php
new file mode 100644
index 000000000..c3d5aa8c6
--- /dev/null
+++ b/engine/tests/api/output.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Test case for ElggAutoP functionality.
+ */
+class ElggCoreOutputAutoPTest extends ElggCoreUnitTest {
+
+ /**
+ * @var ElggAutoP
+ */
+ protected $_autop;
+
+ public function setUp() {
+ $this->_autop = new ElggAutoP();
+ }
+
+ public function testDomRoundtrip() {
+ $d = dir(dirname(dirname(__FILE__)) . '/test_files/output/autop');
+ $in = file_get_contents($d->path . "/domdoc_in.html");
+ $exp = file_get_contents($d->path . "/domdoc_exp.html");
+ $exp = $this->flattenString($exp);
+
+ $doc = new DOMDocument();
+ libxml_use_internal_errors(true);
+ $doc->loadHTML("<html><meta http-equiv='content-type' content='text/html; charset=utf-8'><body>"
+ . $in . '</body></html>');
+ $serialized = $doc->saveHTML();
+ list(,$out) = explode('<body>', $serialized, 2);
+ list($out) = explode('</body>', $out, 2);
+ $out = $this->flattenString($out);
+
+ $this->assertEqual($exp, $out, "DOMDocument's parsing/serialization roundtrip");
+ }
+
+ public function testProcess() {
+ $data = $this->provider();
+ foreach ($data as $row) {
+ list($test, $in, $exp) = $row;
+ $exp = $this->flattenString($exp);
+ $out = $this->_autop->process($in);
+ $out = $this->flattenString($out);
+
+ $this->assertEqual($exp, $out, "Equality case {$test}");
+ }
+ }
+
+ public function provider() {
+ $d = dir(dirname(dirname(__FILE__)) . '/test_files/output/autop');
+ $tests = array();
+ while (false !== ($entry = $d->read())) {
+ if (preg_match('/^([a-z\\-]+)\.in\.html$/i', $entry, $m)) {
+ $tests[] = $m[1];
+ }
+ }
+
+ $data = array();
+ foreach ($tests as $test) {
+ $data[] = array(
+ $test,
+ file_get_contents($d->path . '/' . "{$test}.in.html"),
+ file_get_contents($d->path . '/' . "{$test}.exp.html"),
+ );
+ }
+ return $data;
+ }
+
+ /**
+ * Different versions of PHP return different whitespace between tags.
+ * Removing all line breaks normalizes that.
+ */
+ public function flattenString($string) {
+ $r = preg_replace('/[\n\r]+/', '', $string);
+ return $r;
+ }
+} \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/block-a.exp.norun.html b/engine/tests/test_files/output/autop/block-a.exp.norun.html
new file mode 100644
index 000000000..addf29dec
--- /dev/null
+++ b/engine/tests/test_files/output/autop/block-a.exp.norun.html
@@ -0,0 +1,6 @@
+
+<p>HTML5 allows A to contain block-level content</p>
+<a href="foo"><h3>A treated as block</h3>
+<p>Read more</p>
+</a>
+<p><a href="foo">A treated as<br /> inline</a></p>
diff --git a/engine/tests/test_files/output/autop/block-a.in.norun.html b/engine/tests/test_files/output/autop/block-a.in.norun.html
new file mode 100644
index 000000000..fc2dac43a
--- /dev/null
+++ b/engine/tests/test_files/output/autop/block-a.in.norun.html
@@ -0,0 +1,9 @@
+HTML5 allows A to contain block-level content
+<a href="foo">
+
+ <h3>A treated as block</h3>
+
+ Read more
+</a>
+<a href="foo">A treated as
+ inline</a>
diff --git a/engine/tests/test_files/output/autop/domdoc_exp.html b/engine/tests/test_files/output/autop/domdoc_exp.html
new file mode 100644
index 000000000..8480c1083
--- /dev/null
+++ b/engine/tests/test_files/output/autop/domdoc_exp.html
@@ -0,0 +1,46 @@
+›
+Vietnamese - Tiếng Việt
+
+<h1>h1</h1>
+<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em> <span style="background-color: #ffff00; "></span></p>
+<h2>h2</h2>
+<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p>
+<h3>h3</h3>
+<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p>
+<blockquote>
+ <p>Blockquoted paragraph</p>
+</blockquote>
+<p>Paragraph following blockquote</p>
+<ul><li>Unordered</li>
+ <li>List</li>
+</ul><p>Paragraph between lists</p>
+<ol><li>Ordered</li>
+ <li>List</li>
+</ol><p>Paragraph between lists</p>
+<ul><li>OL list</li>
+ <li>nested<ol><li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul><p>Paragraph between lists</p>
+<table border="0"><tbody><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=0</td>
+ </tr></tbody></table><p>Paragraph</p>
+<ol><li>UL list</li>
+ <li>nested
+ <ul><li>inside a</li>
+ <li>OL list</li>
+ </ul></li>
+</ol><p>Paragraph between tables</p>
+<table border="1" cellpadding="5"><tbody><tr><td>Table with border=1</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>cellpadding = 5</td>
+ </tr></tbody></table><p>Paragraph between tables</p>
+<table border="2"><tbody><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=2</td>
+ </tr></tbody></table> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/domdoc_in.html b/engine/tests/test_files/output/autop/domdoc_in.html
new file mode 100644
index 000000000..4c465b435
--- /dev/null
+++ b/engine/tests/test_files/output/autop/domdoc_in.html
@@ -0,0 +1,80 @@
+&#8250;
+&nbsp;
+Vietnamese - Tiếng Việt
+
+<h1>h1</h1>
+<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em>&nbsp;<span style="background-color: #ffff00; "></span></p>
+<h2>h2</h2>
+<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p>
+<h3>h3</h3>
+<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p>
+<blockquote>
+ <p>Blockquoted paragraph</p>
+</blockquote>
+<p>Paragraph following blockquote</p>
+<ul>
+ <li>Unordered</li>
+ <li>List</li>
+</ul>
+<p>Paragraph between lists</p>
+<ol>
+ <li>Ordered</li>
+ <li>List</li>
+</ol>
+<p>Paragraph between lists</p>
+<ul>
+ <li>OL list</li>
+ <li>nested<ol>
+ <li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul>
+<p>Paragraph between lists</p>
+<table border="0">
+ <tbody>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=0</td>
+ </tr>
+ </tbody>
+</table>
+<p>Paragraph</p>
+<ol>
+ <li>UL list</li>
+ <li>nested
+ <ul>
+ <li>inside a</li>
+ <li>OL list</li>
+ </ul>
+ </li>
+</ol>
+<p>Paragraph between tables</p>
+<table border="1" cellpadding="5">
+ <tbody>
+ <tr>
+ <td>Table with border=1</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>cellpadding = 5</td>
+ </tr>
+ </tbody>
+</table>
+<p>Paragraph between tables</p>
+<table border="2">
+ <tbody>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=2</td>
+ </tr>
+ </tbody>
+</table> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/typical-post.exp.html b/engine/tests/test_files/output/autop/typical-post.exp.html
new file mode 100644
index 000000000..f9d75a114
--- /dev/null
+++ b/engine/tests/test_files/output/autop/typical-post.exp.html
@@ -0,0 +1,84 @@
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<p><img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150">Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.</p>
+
+<p>Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.</p>
+<h3>Donec at massa ante, sagittis fermentum urna.</h3><blockquote>
+<p>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.</p>
+
+<p>[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150">[/caption]</p>
+
+<p>Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.</p>
+
+<p>Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</p>
+</blockquote>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.</p>
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre><ul><li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+<p>Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.</p>
+
+<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object></p>
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<p><img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150">Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.</p>
+
+<p>Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.</p>
+<h3>Donec at massa ante, sagittis fermentum urna.</h3><blockquote>
+<p>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.</p>
+
+<p>[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150">[/caption]</p>
+
+<p>Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.</p>
+
+<p>Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</p>
+</blockquote>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.</p>
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre><ul><li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+<p>Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.</p>
+
+<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object></p>
diff --git a/engine/tests/test_files/output/autop/typical-post.in.html b/engine/tests/test_files/output/autop/typical-post.in.html
new file mode 100644
index 000000000..6e4984cc4
--- /dev/null
+++ b/engine/tests/test_files/output/autop/typical-post.in.html
@@ -0,0 +1,89 @@
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150" />Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.
+
+Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.
+<h3>Donec at massa ante, sagittis fermentum urna.</h3>
+<blockquote>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.
+
+[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150" />[/caption]
+
+Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.
+
+Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</blockquote>
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.
+
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre>
+<ul>
+ <li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.
+
+<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object>
+
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150" />Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.
+
+Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.
+<h3>Donec at massa ante, sagittis fermentum urna.</h3>
+<blockquote>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.
+
+[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150" />[/caption]
+
+Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.
+
+Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</blockquote>
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.
+
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre>
+<ul>
+ <li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.
+
+<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wp-welcome.exp.html b/engine/tests/test_files/output/autop/wp-welcome.exp.html
new file mode 100644
index 000000000..2f612e3dd
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wp-welcome.exp.html
@@ -0,0 +1,22 @@
+
+<p>Welcome to WordPress! This post contains important information. After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.</p>
+
+<p>First things first:</p>
+<ul><li><a href="%1%24s" title="Subscribe to the WordPress mailing list for Release Notifications">Subscribe to the WordPress mailing list for release notifications</a></li>
+</ul>
+<p>As a subscriber, you will receive an email every time an update is available (and only then). This will make it easier to keep your site up to date, and secure from evildoers.<br />When a new version is released, <a href="%2%24s" title="If you are already logged in, this will take you directly to the Dashboard">log in to the Dashboard</a> and follow the instructions.<br />Upgrading is a couple of clicks!</p>
+
+<p>Then you can start enjoying the WordPress experience:</p>
+<ul><li>Edit your personal information at <a href="%3%24s" title="Edit settings like your password, your display name and your contact information">Users &#8250; Your Profile</a></li>
+ <li>Start publishing at <a href="%4%24s" title="Create a new post">Posts &#8250; Add New</a> and at <a href="%5%24s" title="Create a new page">Pages &#8250; Add New</a></li>
+ <li>Browse and install plugins at <a href="%6%24s" title="Browse and install plugins at the official WordPress repository directly from your Dashboard">Plugins &#8250; Add New</a></li>
+ <li>Browse and install themes at <a href="%7%24s" title="Browse and install themes at the official WordPress repository directly from your Dashboard">Appearance &#8250; Add New Themes</a></li>
+ <li>Modify and prettify your website&#8217;s links at <a href="%8%24s" title="For example, select a link structure like: http://example.com/1999/12/post-name">Settings &#8250; Permalinks</a></li>
+ <li>Import content from another system or WordPress site at <a href="%9%24s" title="WordPress comes with importers for the most common publishing systems">Tools &#8250; Import</a></li>
+ <li>Find answers to your questions at the <a href="%10%24s" title="The official WordPress documentation, maintained by the WordPress community">WordPress Codex</a></li>
+</ul>
+<p>To keep this post for reference, <a href="%11%24s" title="Click to edit the content and settings of this post">click to edit it</a>, go to the Publish box and change its Visibility from Public to Private.</p>
+
+<p>Thank you for selecting WordPress. We wish you happy publishing!</p>
+
+<p>PS. Not yet subscribed for update notifications? <a href="%1%24s" title="Subscribe to the WordPress mailing list for Release Notifications">Do it now!</a></p>
diff --git a/engine/tests/test_files/output/autop/wp-welcome.in.html b/engine/tests/test_files/output/autop/wp-welcome.in.html
new file mode 100644
index 000000000..338ede73f
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wp-welcome.in.html
@@ -0,0 +1,25 @@
+Welcome to WordPress! This post contains important information. After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.
+
+First things first:
+<ul>
+ <li><a href="%1$s" title="Subscribe to the WordPress mailing list for Release Notifications">Subscribe to the WordPress mailing list for release notifications</a></li>
+</ul>
+As a subscriber, you will receive an email every time an update is available (and only then). This will make it easier to keep your site up to date, and secure from evildoers.
+When a new version is released, <a href="%2$s" title="If you are already logged in, this will take you directly to the Dashboard">log in to the Dashboard</a> and follow the instructions.
+Upgrading is a couple of clicks!
+
+Then you can start enjoying the WordPress experience:
+<ul>
+ <li>Edit your personal information at <a href="%3$s" title="Edit settings like your password, your display name and your contact information">Users &#8250; Your Profile</a></li>
+ <li>Start publishing at <a href="%4$s" title="Create a new post">Posts &#8250; Add New</a> and at <a href="%5$s" title="Create a new page">Pages &#8250; Add New</a></li>
+ <li>Browse and install plugins at <a href="%6$s" title="Browse and install plugins at the official WordPress repository directly from your Dashboard">Plugins &#8250; Add New</a></li>
+ <li>Browse and install themes at <a href="%7$s" title="Browse and install themes at the official WordPress repository directly from your Dashboard">Appearance &#8250; Add New Themes</a></li>
+ <li>Modify and prettify your website&#8217;s links at <a href="%8$s" title="For example, select a link structure like: http://example.com/1999/12/post-name">Settings &#8250; Permalinks</a></li>
+ <li>Import content from another system or WordPress site at <a href="%9$s" title="WordPress comes with importers for the most common publishing systems">Tools &#8250; Import</a></li>
+ <li>Find answers to your questions at the <a href="%10$s" title="The official WordPress documentation, maintained by the WordPress community">WordPress Codex</a></li>
+</ul>
+To keep this post for reference, <a href="%11$s" title="Click to edit the content and settings of this post">click to edit it</a>, go to the Publish box and change its Visibility from Public to Private.
+
+Thank you for selecting WordPress. We wish you happy publishing!
+
+PS. Not yet subscribed for update notifications? <a href="%1$s" title="Subscribe to the WordPress mailing list for Release Notifications">Do it now!</a>
diff --git a/engine/tests/test_files/output/autop/wpautop-fails.exp.html b/engine/tests/test_files/output/autop/wpautop-fails.exp.html
new file mode 100644
index 000000000..d018db4ff
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wpautop-fails.exp.html
@@ -0,0 +1,31 @@
+
+<p>paragraph</p>
+
+<p>paragraph</p>
+<div class="whatever"><blockquote>
+<p>paragraph</p>
+</blockquote>
+<p>line</p>
+</div>
+<p>paragraph</p>
+<ul><li>line</li>
+<li>paragraph
+
+paragraph</li>
+</ul>
+<p>paragraph<br />line<br />line</p>
+<pre>Honor
+this whitespace
+</pre>
+<p>paragraph</p>
+<style><!--
+Do not alter!
+--></style>
+<p>paragraph <!-- do not alter --></p>
+<dl><dt>term</dt> <dd>paragraph
+
+<a href="xx"> <img src="yy"></a>
+
+paragraph</dd> </dl><div><a href="xx"> <img src="yy"></a></div>
+<p>Hello <a href="link"><br /><br />World</a></p>
+<p id="abc">Paragraph</p><div>Line</div> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wpautop-fails.in.html b/engine/tests/test_files/output/autop/wpautop-fails.in.html
new file mode 100644
index 000000000..9aa24be59
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wpautop-fails.in.html
@@ -0,0 +1,41 @@
+
+paragraph
+
+paragraph <div class="whatever"><blockquote>
+ paragraph
+ </blockquote>
+ line
+</div>
+
+paragraph
+<ul>
+<li>line</li>
+<li>paragraph
+
+paragraph</li>
+</ul>
+paragraph
+line<br>
+ line
+<pre>Honor
+this whitespace
+</pre>
+paragraph
+<style><!--
+Do not alter!
+--></style>
+paragraph <!-- do not alter -->
+<dl> <dt>term</dt> <dd>paragraph
+
+<a href="xx"> <img src="yy" /> </a>
+
+paragraph</dd> </dl>
+<div><a href="xx"> <img src="yy" /> </a></div>
+
+Hello <a href="link">
+
+World</a>
+
+<p id="abc">Paragraph</p>
+
+<div>Line</div> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wysiwyg-test.exp.html b/engine/tests/test_files/output/autop/wysiwyg-test.exp.html
new file mode 100644
index 000000000..1f23d6154
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wysiwyg-test.exp.html
@@ -0,0 +1,51 @@
+
+<p>&nbps;<br />&#8820;</p>
+<h1>h1</h1>
+<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em>&nbsp;<span style="background-color: #ffff00; "></span></p>
+<h2>h2</h2>
+<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p>
+<h3>h3</h3>
+<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p>
+<blockquote>
+<p>Blockquoted paragraph</p>
+</blockquote>
+<p>Paragraph following blockquote</p>
+<ul><li>Unordered</li>
+ <li>List</li>
+</ul>
+<p>Paragraph between lists</p>
+<ol><li>Ordered</li>
+ <li>List</li>
+</ol>
+<p>Paragraph between lists</p>
+<ul><li>OL list</li>
+ <li>nested
+ <ol><li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul>
+<p>Paragraph between lists</p>
+<table border="0"><tbody><tr></tr><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=0</td>
+ </tr></tbody></table>
+<p>Paragraph</p>
+<ol><li>UL list</li>
+ <li>nested
+ <ul><li>inside a</li>
+ <li>OL list</li>
+ </ul></li>
+</ol>
+<p>Paragraph between tables</p>
+<table border="1" cellpadding="5"><tbody><tr><td>Table with border=1</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>cellpadding = 5</td>
+ </tr></tbody></table>
+<p>Paragraph between tables</p>
+<table border="2"><tbody><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=2</td>
+ </tr></tbody></table> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wysiwyg-test.in.html b/engine/tests/test_files/output/autop/wysiwyg-test.in.html
new file mode 100644
index 000000000..733b0e2ec
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wysiwyg-test.in.html
@@ -0,0 +1,79 @@
+&nbps;
+&#8820;
+<h1>h1</h1>
+Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em>&nbsp;<span style="background-color: #ffff00; "></span>
+<h2>h2</h2>
+Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span>
+<h3>h3</h3>
+Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span>
+<blockquote>Blockquoted paragraph</blockquote>
+Paragraph following blockquote
+<ul>
+ <li>Unordered</li>
+ <li>List</li>
+</ul>
+Paragraph between lists
+<ol>
+ <li>Ordered</li>
+ <li>List</li>
+</ol>
+Paragraph between lists
+<ul>
+ <li>OL list</li>
+ <li>nested
+ <ol>
+ <li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul>
+Paragraph between lists
+<table border="0">
+ <tbody>
+ <tr>
+ </tr>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=0</td>
+ </tr>
+ </tbody>
+</table>
+Paragraph
+<ol>
+ <li>UL list</li>
+ <li>nested
+ <ul>
+ <li>inside a</li>
+ <li>OL list</li>
+ </ul>
+ </li>
+</ol>
+Paragraph between tables
+<table border="1" cellpadding="5">
+ <tbody>
+ <tr>
+ <td>Table with border=1</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>cellpadding = 5</td>
+ </tr>
+ </tbody>
+</table>
+Paragraph between tables
+<table border="2">
+ <tbody>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=2</td>
+ </tr>
+ </tbody>
+</table> \ No newline at end of file