diff options
Diffstat (limited to 'engine/classes')
32 files changed, 898 insertions, 253 deletions
diff --git a/engine/classes/ElggAccess.php b/engine/classes/ElggAccess.php index 6f8d9bb4b..0aed477fc 100644 --- a/engine/classes/ElggAccess.php +++ b/engine/classes/ElggAccess.php @@ -16,6 +16,7 @@ class ElggAccess { */ private $ignore_access; + // @codingStandardsIgnoreStart /** * Get current ignore access setting. * @@ -26,6 +27,7 @@ class ElggAccess { elgg_deprecated_notice('ElggAccess::get_ignore_access() is deprecated by ElggAccess::getIgnoreAccess()', 1.8); return $this->getIgnoreAccess(); } + // @codingStandardsIgnoreEnd /** * Get current ignore access setting. @@ -36,6 +38,7 @@ class ElggAccess { return $this->ignore_access; } + // @codingStandardsIgnoreStart /** * Set ignore access. * @@ -49,6 +52,7 @@ class ElggAccess { elgg_deprecated_notice('ElggAccess::set_ignore_access() is deprecated by ElggAccess::setIgnoreAccess()', 1.8); return $this->setIgnoreAccess($ignore); } + // @codingStandardsIgnoreEnd /** * Set ignore access. diff --git a/engine/classes/ElggAnnotation.php b/engine/classes/ElggAnnotation.php index 511b5151f..175e7049d 100644 --- a/engine/classes/ElggAnnotation.php +++ b/engine/classes/ElggAnnotation.php @@ -11,6 +11,9 @@ * @package Elgg.Core * @subpackage DataModel.Annotations * @link http://docs.elgg.org/DataModel/Annotations + * + * @property string $value_type + * @property string $enabled */ class ElggAnnotation extends ElggExtender { @@ -56,6 +59,8 @@ class ElggAnnotation extends ElggExtender { * Save this instance * * @return int an object id + * + * @throws IOException */ function save() { if ($this->id > 0) { diff --git a/engine/classes/ElggAttributeLoader.php b/engine/classes/ElggAttributeLoader.php index 602bb8bae..ffc80b02d 100644 --- a/engine/classes/ElggAttributeLoader.php +++ b/engine/classes/ElggAttributeLoader.php @@ -4,6 +4,9 @@ * Loads ElggEntity attributes from DB or validates those passed in via constructor * * @access private + * + * @package Elgg.Core + * @subpackage DataModel */ class ElggAttributeLoader { @@ -21,7 +24,7 @@ class ElggAttributeLoader { 'time_created', 'time_updated', 'last_action', - 'enabled' + 'enabled', ); /** @@ -65,9 +68,11 @@ class ElggAttributeLoader { public $full_loader = ''; /** - * @param string $class class of object being loaded - * @param string $required_type entity type this is being used to populate - * @param array $initialized_attrs attributes after initializeAttributes() has been run + * Constructor + * + * @param string $class class of object being loaded + * @param string $required_type entity type this is being used to populate + * @param array $initialized_attrs attributes after initializeAttributes() has been run * @throws InvalidArgumentException */ public function __construct($class, $required_type, array $initialized_attrs) { @@ -87,14 +92,33 @@ class ElggAttributeLoader { $this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names); } + /** + * Get primary attributes missing that are missing + * + * @param stdClass $row Database row + * @return array + */ protected function isMissingPrimaries($row) { return array_diff(self::$primary_attr_names, array_keys($row)) !== array(); } + /** + * Get secondary attributes that are missing + * + * @param stdClass $row Database row + * @return array + */ protected function isMissingSecondaries($row) { return array_diff($this->secondary_attr_names, array_keys($row)) !== array(); } + /** + * Check that the type is correct + * + * @param stdClass $row Database row + * @return void + * @throws InvalidClassException + */ protected function checkType($row) { if ($row['type'] !== $this->required_type) { $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($row['guid'], $this->class)); @@ -148,11 +172,11 @@ class ElggAttributeLoader { if (!is_callable($this->primary_loader)) { throw new LogicException('Primary attribute loader must be callable'); } - if (!$this->requires_access_control) { + if ($this->requires_access_control) { + $fetched = (array) call_user_func($this->primary_loader, $row['guid']); + } else { $ignoring_access = elgg_set_ignore_access(); - } - $fetched = (array) call_user_func($this->primary_loader, $row['guid']); - if (!$this->requires_access_control) { + $fetched = (array) call_user_func($this->primary_loader, $row['guid']); elgg_set_ignore_access($ignoring_access); } if (!$fetched) { @@ -176,6 +200,8 @@ class ElggAttributeLoader { // saved, these are stored w/ type "site", but with no sites_entity row. These // are probably only created in the unit tests. // @todo Don't save vanilla ElggEntities with type "site" + + $row = $this->filterAddedColumns($row); $row['guid'] = (int) $row['guid']; return $row; } @@ -185,15 +211,38 @@ class ElggAttributeLoader { } } - // loading complete: re-check missing and check type - if (($was_missing_primaries && $this->isMissingPrimaries($row)) - || ($was_missing_secondaries && $this->isMissingSecondaries($row))) { - throw new LogicException('Attribute loaders failed to return proper attributes'); - } + $row = $this->filterAddedColumns($row); + + // Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let + // this pass so the upgrades can run. - // guid needs to be an int http://trac.elgg.org/ticket/4111 + // guid needs to be an int https://github.com/elgg/elgg/issues/4111 $row['guid'] = (int) $row['guid']; return $row; } + + /** + * Filter out keys returned by the query which should not appear in the entity's attributes + * + * @param array $row All columns from the query + * @return array Columns acceptable for the entity's attributes + */ + protected function filterAddedColumns($row) { + // make an array with keys as acceptable attribute names + $acceptable_attrs = self::$primary_attr_names; + array_splice($acceptable_attrs, count($acceptable_attrs), 0, $this->secondary_attr_names); + $acceptable_attrs = array_combine($acceptable_attrs, $acceptable_attrs); + + // @todo remove these when #4584 is in place + $acceptable_attrs['tables_split'] = true; + $acceptable_attrs['tables_loaded'] = true; + + foreach ($row as $key => $val) { + if (!isset($acceptable_attrs[$key])) { + unset($row[$key]); + } + } + return $row; + } } diff --git a/engine/classes/ElggAutoP.php b/engine/classes/ElggAutoP.php index 89d77e583..05842d1b2 100644 --- a/engine/classes/ElggAutoP.php +++ b/engine/classes/ElggAutoP.php @@ -7,6 +7,9 @@ * * In DIV elements, Ps are only added when there would be at * least two of them. + * + * @package Elgg.Core + * @subpackage Output */ class ElggAutoP { @@ -51,8 +54,12 @@ class ElggAutoP { protected $_alterList = 'article aside blockquote body details div footer header section'; + /** @var string */ protected $_unique = ''; + /** + * Constructor + */ public function __construct() { $this->_blocks = preg_split('@\\s+@', $this->_blocks); $this->_descendList = preg_split('@\\s+@', $this->_descendList); @@ -98,25 +105,34 @@ class ElggAutoP { $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); + // Do not load entities. May be unnecessary, better safe than sorry + $disable_load_entities = libxml_disable_entity_loader(true); + if (!$this->_doc->loadHTML("<html><meta http-equiv='content-type' " . "content='text/html; charset={$this->encoding}'><body>{$html}</body>" . "</html>")) { + + libxml_disable_entity_loader($disable_load_entities); return false; } + libxml_disable_entity_loader($disable_load_entities); + $this->_xpath = new DOMXPath($this->_doc); // start processing recursively at the BODY element $nodeList = $this->_xpath->query('//body[1]'); - $this->_addParagraphs($nodeList->item(0)); + $this->addParagraphs($nodeList->item(0)); // serialize back to HTML $html = $this->_doc->saveHTML(); + // Note: we create <autop> elements, which will later be converted to paragraphs + // 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>'), @@ -126,14 +142,22 @@ class ElggAutoP { // re-parse so we can handle new AUTOP elements + // Do not load entities. May be unnecessary, better safe than sorry + $disable_load_entities = libxml_disable_entity_loader(true); + if (!$this->_doc->loadHTML($html)) { + libxml_disable_entity_loader($disable_load_entities); return false; } + + libxml_disable_entity_loader($disable_load_entities); + // 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) { + /* @var DOMElement $autop */ $hasContent = false; if (trim($autop->textContent) !== '') { $hasContent = true; @@ -146,17 +170,19 @@ class ElggAutoP { } } if (!$hasContent) { - // strip w/ preg_replace later (faster than moving nodes out) + // mark to be later replaced w/ preg_replace (faster than moving nodes out) $autop->setAttribute("r", "1"); } } - // remove a single AUTOP inside certain elements + // If a DIV contains a single AUTOP, remove it foreach ($this->_xpath->query('//div') as $el) { + /* @var DOMElement $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"); + $firstAutop = $autops->item(0); + /* @var DOMElement $firstAutop */ + $firstAutop->setAttribute("r", "1"); } } @@ -182,15 +208,16 @@ class ElggAutoP { /** * Add P and BR elements as necessary * - * @param DOMElement $el + * @param DOMElement $el DOM element + * @return void */ - protected function _addParagraphs(DOMElement $el) { - // no need to recurse, just queue up + protected function addParagraphs(DOMElement $el) { + // no need to call recursively, 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 + // 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 @@ -216,16 +243,16 @@ class ElggAutoP { $isElement = ($node->nodeType === XML_ELEMENT_NODE); if ($isElement) { - $elName = $node->nodeName; + $isBlock = in_array($node->nodeName, $this->_blocks); + } else { + $isBlock = false; } - $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))); + || ($node->nextSibling->nodeType === XML_ELEMENT_NODE + && in_array($node->nextSibling->nodeName, $this->_blocks))); if ($isElement) { $isFollowingBr = ($node->nodeName === 'br'); } @@ -258,7 +285,7 @@ class ElggAutoP { if ($isBlock) { if (in_array($node->nodeName, $this->_descendList)) { $elsToProcess[] = $node; - //$this->_addParagraphs($node); + //$this->addParagraphs($node); } } $openP = true; diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php index c1a77a0d9..d810ea066 100644 --- a/engine/classes/ElggBatch.php +++ b/engine/classes/ElggBatch.php @@ -150,6 +150,20 @@ class ElggBatch private $incrementOffset = true; /** + * Entities that could not be instantiated during a fetch + * + * @var stdClass[] + */ + private $incompleteEntities = array(); + + /** + * Total number of incomplete entities fetched + * + * @var int + */ + private $totalIncompletes = 0; + + /** * Batches operations on any elgg_get_*() or compatible function that supports * an options array. * @@ -222,16 +236,22 @@ class ElggBatch } /** + * Tell the process that an entity was incomplete during a fetch + * + * @param stdClass $row + * + * @access private + */ + public function reportIncompleteEntity(stdClass $row) { + $this->incompleteEntities[] = $row; + } + + /** * Fetches the next chunk of results * * @return bool */ private function getNextResultsChunk() { - // reset memory caches after first chunk load - if ($this->chunkIndex > 0) { - global $DB_QUERY_CACHE, $ENTITY_CACHE; - $DB_QUERY_CACHE = $ENTITY_CACHE = array(); - } // always reset results. $this->results = array(); @@ -265,27 +285,47 @@ class ElggBatch if ($this->incrementOffset) { $offset = $this->offset + $this->retrievedResults; } else { - $offset = $this->offset; + $offset = $this->offset + $this->totalIncompletes; } $current_options = array( 'limit' => $limit, - 'offset' => $offset + 'offset' => $offset, + '__ElggBatch' => $this, ); $options = array_merge($this->options, $current_options); - $getter = $this->getter; - if (is_string($getter)) { - $this->results = $getter($options); - } else { - $this->results = call_user_func_array($getter, array($options)); + $this->incompleteEntities = array(); + $this->results = call_user_func_array($this->getter, array($options)); + + $num_results = count($this->results); + $num_incomplete = count($this->incompleteEntities); + + $this->totalIncompletes += $num_incomplete; + + if ($this->incompleteEntities) { + // pad the front of the results with nulls representing the incompletes + array_splice($this->results, 0, 0, array_pad(array(), $num_incomplete, null)); + // ...and skip past them + reset($this->results); + for ($i = 0; $i < $num_incomplete; $i++) { + next($this->results); + } } if ($this->results) { $this->chunkIndex++; - $this->resultIndex = 0; - $this->retrievedResults += count($this->results); + + // let the system know we've jumped past the nulls + $this->resultIndex = $num_incomplete; + + $this->retrievedResults += ($num_results + $num_incomplete); + if ($num_results == 0) { + // This fetch was *all* incompletes! We need to fetch until we can either + // offer at least one row to iterate over, or give up. + return $this->getNextResultsChunk(); + } return true; } else { return false; @@ -296,7 +336,8 @@ class ElggBatch * Increment the offset from the original options array? Setting to * false is required for callbacks that delete rows. * - * @param bool $increment + * @param bool $increment Set to false when deleting data + * @return void */ public function setIncrementOffset($increment = true) { $this->incrementOffset = (bool) $increment; diff --git a/engine/classes/ElggCache.php b/engine/classes/ElggCache.php index 4317f4be9..909eab39b 100644 --- a/engine/classes/ElggCache.php +++ b/engine/classes/ElggCache.php @@ -21,6 +21,7 @@ abstract class ElggCache implements ArrayAccess { $this->variables = array(); } + // @codingStandardsIgnoreStart /** * Set a cache variable. * @@ -35,6 +36,7 @@ abstract class ElggCache implements ArrayAccess { elgg_deprecated_notice('ElggCache::set_variable() is deprecated by ElggCache::setVariable()', 1.8); $this->setVariable($variable, $value); } + // @codingStandardsIgnoreEnd /** * Set a cache variable. @@ -52,6 +54,7 @@ abstract class ElggCache implements ArrayAccess { $this->variables[$variable] = $value; } + // @codingStandardsIgnoreStart /** * Get variables for this cache. * @@ -65,6 +68,7 @@ abstract class ElggCache implements ArrayAccess { elgg_deprecated_notice('ElggCache::get_variable() is deprecated by ElggCache::getVariable()', 1.8); return $this->getVariable($variable); } + // @codingStandardsIgnoreEnd /** * Get variables for this cache. diff --git a/engine/classes/ElggCrypto.php b/engine/classes/ElggCrypto.php new file mode 100644 index 000000000..317d371e4 --- /dev/null +++ b/engine/classes/ElggCrypto.php @@ -0,0 +1,208 @@ +<?php +/** + * ElggCrypto + * + * @package Elgg.Core + * @subpackage Crypto + * + * @access private + */ +class ElggCrypto { + + /** + * Character set for temp passwords (no risk of embedded profanity/glyphs that look similar) + */ + const CHARS_PASSWORD = 'bcdfghjklmnpqrstvwxyz2346789'; + + /** + * Generate a string of highly randomized bytes (over the full 8-bit range). + * + * @param int $length Number of bytes needed + * @return string Random bytes + * + * @author George Argyros <argyros.george@gmail.com> + * @copyright 2012, George Argyros. All rights reserved. + * @license Modified BSD + * @link https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP/blob/master/srand.php Original + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + public function getRandomBytes($length) { + /** + * Our primary choice for a cryptographic strong randomness function is + * openssl_random_pseudo_bytes. + */ + $SSLstr = '4'; // http://xkcd.com/221/ + if (function_exists('openssl_random_pseudo_bytes') + && (version_compare(PHP_VERSION, '5.3.4') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) { + $SSLstr = openssl_random_pseudo_bytes($length, $strong); + if ($strong) { + return $SSLstr; + } + } + + /** + * If mcrypt extension is available then we use it to gather entropy from + * the operating system's PRNG. This is better than reading /dev/urandom + * directly since it avoids reading larger blocks of data than needed. + * Older versions of mcrypt_create_iv may be broken or take too much time + * to finish so we only use this function with PHP 5.3.7 and above. + * @see https://bugs.php.net/bug.php?id=55169 + */ + if (function_exists('mcrypt_create_iv') + && (version_compare(PHP_VERSION, '5.3.7') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) { + $str = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + if ($str !== false) { + return $str; + } + } + + /** + * No build-in crypto randomness function found. We collect any entropy + * available in the PHP core PRNGs along with some filesystem info and memory + * stats. To make this data cryptographically strong we add data either from + * /dev/urandom or if its unavailable, we gather entropy by measuring the + * time needed to compute a number of SHA-1 hashes. + */ + $str = ''; + $bits_per_round = 2; // bits of entropy collected in each clock drift round + $msec_per_round = 400; // expected running time of each round in microseconds + $hash_len = 20; // SHA-1 Hash length + $total = $length; // total bytes of entropy to collect + + $handle = @fopen('/dev/urandom', 'rb'); + if ($handle && function_exists('stream_set_read_buffer')) { + @stream_set_read_buffer($handle, 0); + } + + do { + $bytes = ($total > $hash_len) ? $hash_len : $total; + $total -= $bytes; + + //collect any entropy available from the PHP system and filesystem + $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; + $entropy .= implode('', @fstat(@fopen(__FILE__, 'r'))); + $entropy .= memory_get_usage() . getmypid(); + $entropy .= serialize($_ENV) . serialize($_SERVER); + if (function_exists('posix_times')) { + $entropy .= serialize(posix_times()); + } + if (function_exists('zend_thread_id')) { + $entropy .= zend_thread_id(); + } + + if ($handle) { + $entropy .= @fread($handle, $bytes); + } else { + // Measure the time that the operations will take on average + for ($i = 0; $i < 3; $i++) { + $c1 = microtime(true); + $var = sha1(mt_rand()); + for ($j = 0; $j < 50; $j++) { + $var = sha1($var); + } + $c2 = microtime(true); + $entropy .= $c1 . $c2; + } + + // Based on the above measurement determine the total rounds + // in order to bound the total running time. + $rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000)); + + // Take the additional measurements. On average we can expect + // at least $bits_per_round bits of entropy from each measurement. + $iter = $bytes * (int) (ceil(8 / $bits_per_round)); + + for ($i = 0; $i < $iter; $i++) { + $c1 = microtime(); + $var = sha1(mt_rand()); + for ($j = 0; $j < $rounds; $j++) { + $var = sha1($var); + } + $c2 = microtime(); + $entropy .= $c1 . $c2; + } + } + + // We assume sha1 is a deterministic extractor for the $entropy variable. + $str .= sha1($entropy, true); + + } while ($length > strlen($str)); + + if ($handle) { + @fclose($handle); + } + + return substr($str, 0, $length); + } + + /** + * Generate a random string of specified length. + * + * Uses supplied character list for generating the new string. + * If no character list provided - uses Base64 URL character set. + * + * @param int $length Desired length of the string + * @param string|null $chars Characters to be chosen from randomly. If not given, the Base64 URL + * charset will be used. + * + * @return string The random string + * + * @throws InvalidArgumentException + * + * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * + * @see https://github.com/zendframework/zf2/blob/master/library/Zend/Math/Rand.php#L179 + */ + public static function getRandomString($length, $chars = null) { + if ($length < 1) { + throw new InvalidArgumentException('Length should be >= 1'); + } + + if (empty($chars)) { + $numBytes = ceil($length * 0.75); + $bytes = self::getRandomBytes($numBytes); + $string = substr(rtrim(base64_encode($bytes), '='), 0, $length); + + // Base64 URL + return strtr($string, '+/', '-_'); + } + + $listLen = strlen($chars); + + if ($listLen == 1) { + return str_repeat($chars, $length); + } + + $bytes = self::getRandomBytes($length); + $pos = 0; + $result = ''; + for ($i = 0; $i < $length; $i++) { + $pos = ($pos + ord($bytes[$i])) % $listLen; + $result .= $chars[$pos]; + } + + return $result; + } +} diff --git a/engine/classes/ElggData.php b/engine/classes/ElggData.php index 3470ee1cf..4f843cde4 100644 --- a/engine/classes/ElggData.php +++ b/engine/classes/ElggData.php @@ -5,6 +5,9 @@ * * @package Elgg.Core * @subpackage DataModel + * + * @property int $owner_guid + * @property int $time_created */ abstract class ElggData implements Loggable, // Can events related to this object class be logged @@ -23,6 +26,7 @@ abstract class ElggData implements */ protected $attributes = array(); + // @codingStandardsIgnoreStart /** * Initialise the attributes array. * @@ -33,16 +37,15 @@ abstract class ElggData implements * Passing false returns false. Core constructors always pass false. * Does nothing either way since attributes are initialized by the time * this is called. - * @return false|void False is + * @return void * @deprecated 1.8 Use initializeAttributes() */ protected function initialise_attributes($pre18_api = true) { if ($pre18_api) { elgg_deprecated_notice('initialise_attributes() is deprecated by initializeAttributes()', 1.8); - } else { - return false; } } + // @codingStandardsIgnoreEnd /** * Initialize the attributes array. @@ -111,7 +114,7 @@ abstract class ElggData implements * @param string $name The attribute to set * @param mixed $value The value to set it to * - * @return The success of your set funtion? + * @return bool The success of your set function? */ abstract protected function set($name, $value); @@ -195,7 +198,7 @@ abstract class ElggData implements * * @see Iterator::current() * - * @return void + * @return mixed */ public function current() { return current($this->attributes); @@ -206,7 +209,7 @@ abstract class ElggData implements * * @see Iterator::key() * - * @return void + * @return string */ public function key() { return key($this->attributes); @@ -228,7 +231,7 @@ abstract class ElggData implements * * @see Iterator::valid() * - * @return void + * @return bool */ public function valid() { return $this->valid; @@ -266,12 +269,13 @@ abstract class ElggData implements * * @param mixed $key Name * - * @return void + * @return mixed */ public function offsetGet($key) { if (array_key_exists($key, $this->attributes)) { return $this->attributes[$key]; } + return null; } /** diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php index 7aace43ba..6e2354012 100644 --- a/engine/classes/ElggDiskFilestore.php +++ b/engine/classes/ElggDiskFilestore.php @@ -60,6 +60,7 @@ class ElggDiskFilestore extends ElggFilestore { $path = substr($fullname, 0, $ls); $name = substr($fullname, $ls); + // @todo $name is unused, remove it or do we need to fix something? // Try and create the directory try { @@ -108,7 +109,7 @@ class ElggDiskFilestore extends ElggFilestore { * * @param resource $f File pointer resource * @param int $length The number of bytes to read - * @param inf $offset The number of bytes to start after + * @param int $offset The number of bytes to start after * * @return mixed Contents of file or false on fail. */ @@ -193,11 +194,14 @@ class ElggDiskFilestore extends ElggFilestore { } /** - * Returns the filename as saved on disk for an ElggFile object + * Get the filename as saved on disk for an ElggFile object + * + * Returns an empty string if no filename set * * @param ElggFile $file File object * * @return string The full path of where the file is stored + * @throws InvalidParameterException */ public function getFilenameOnFilestore(ElggFile $file) { $owner_guid = $file->getOwnerGuid(); @@ -211,7 +215,12 @@ class ElggDiskFilestore extends ElggFilestore { throw new InvalidParameterException($msg); } - return $this->dir_root . $this->makefileMatrix($owner_guid) . $file->getFilename(); + $filename = $file->getFilename(); + if (!$filename) { + return ''; + } + + return $this->dir_root . $this->makeFileMatrix($owner_guid) . $filename; } /** @@ -219,7 +228,7 @@ class ElggDiskFilestore extends ElggFilestore { * * @param ElggFile $file File object * - * @return mixed + * @return string */ public function grabFile(ElggFile $file) { return file_get_contents($file->getFilenameOnFilestore()); @@ -233,6 +242,9 @@ class ElggDiskFilestore extends ElggFilestore { * @return bool */ public function exists(ElggFile $file) { + if (!$file->getFilename()) { + return false; + } return file_exists($this->getFilenameOnFilestore($file)); } @@ -246,12 +258,13 @@ class ElggDiskFilestore extends ElggFilestore { */ public function getSize($prefix = '', $container_guid) { if ($container_guid) { - return get_dir_size($this->dir_root . $this->makefileMatrix($container_guid) . $prefix); + return get_dir_size($this->dir_root . $this->makeFileMatrix($container_guid) . $prefix); } else { return false; } } + // @codingStandardsIgnoreStart /** * Create a directory $dirroot * @@ -266,6 +279,7 @@ class ElggDiskFilestore extends ElggFilestore { return $this->makeDirectoryRoot($dirroot); } + // @codingStandardsIgnoreEnd /** * Create a directory $dirroot @@ -285,6 +299,7 @@ class ElggDiskFilestore extends ElggFilestore { return true; } + // @codingStandardsIgnoreStart /** * Multibyte string tokeniser. * @@ -315,30 +330,31 @@ class ElggDiskFilestore extends ElggFilestore { } else { return str_split($string); } - - return false; } + // @codingStandardsIgnoreEnd + // @codingStandardsIgnoreStart /** * Construct a file path matrix for an entity. * * @param int $identifier The guide of the entity to store the data under. * - * @return str The path where the entity's data will be stored. + * @return string The path where the entity's data will be stored. * @deprecated 1.8 Use ElggDiskFilestore::makeFileMatrix() */ protected function make_file_matrix($identifier) { elgg_deprecated_notice('ElggDiskFilestore::make_file_matrix() is deprecated by ::makeFileMatrix()', 1.8); - return $this->makefileMatrix($identifier); + return $this->makeFileMatrix($identifier); } + // @codingStandardsIgnoreEnd /** * Construct a file path matrix for an entity. * * @param int $guid The guide of the entity to store the data under. * - * @return str The path where the entity's data will be stored. + * @return string The path where the entity's data will be stored. */ protected function makeFileMatrix($guid) { $entity = get_entity($guid); @@ -352,6 +368,7 @@ class ElggDiskFilestore extends ElggFilestore { return "$time_created/$entity->guid/"; } + // @codingStandardsIgnoreStart /** * Construct a filename matrix. * @@ -363,13 +380,14 @@ class ElggDiskFilestore extends ElggFilestore { * * @param int $guid The entity to contrust a matrix for * - * @return str The + * @return string The */ protected function user_file_matrix($guid) { elgg_deprecated_notice('ElggDiskFilestore::user_file_matrix() is deprecated by ::makeFileMatrix()', 1.8); return $this->makeFileMatrix($guid); } + // @codingStandardsIgnoreEnd /** * Returns a list of attributes to save to the database when saving diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index 929abceb2..a563f6fad 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -24,7 +24,7 @@ * * @package Elgg.Core * @subpackage DataModel.Entities - * + * * @property string $type object, user, group, or site (read-only after save) * @property string $subtype Further clarifies the nature of the entity (read-only after save) * @property int $guid The unique identifier for this entity (read only) @@ -34,6 +34,7 @@ * @property int $access_id Specifies the visibility level of this entity * @property int $time_created A UNIX timestamp of when the entity was created (read-only, set on first save) * @property int $time_updated A UNIX timestamp of when the entity was last updated (automatically updated on save) + * @property-read string $enabled */ abstract class ElggEntity extends ElggData implements Notable, // Calendar interface @@ -351,8 +352,8 @@ abstract class ElggEntity extends ElggData implements 'limit' => 0 ); // @todo in 1.9 make this return false if can't add metadata - // http://trac.elgg.org/ticket/4520 - // + // https://github.com/elgg/elgg/issues/4520 + // // need to remove access restrictions right now to delete // because this is the expected behavior $ia = elgg_set_ignore_access(true); @@ -374,12 +375,11 @@ abstract class ElggEntity extends ElggData implements } return $result; - } - - // unsaved entity. store in temp array - // returning single entries instead of an array of 1 element is decided in - // getMetaData(), just like pulling from the db. - else { + } else { + // unsaved entity. store in temp array + // returning single entries instead of an array of 1 element is decided in + // getMetaData(), just like pulling from the db. + // // if overwrite, delete first if (!$multiple || !isset($this->temp_metadata[$name])) { $this->temp_metadata[$name] = array(); @@ -940,7 +940,7 @@ abstract class ElggEntity extends ElggData implements * @param ElggMetadata $metadata The piece of metadata to specifically check * @param int $user_guid The user GUID, optionally (default: logged in user) * - * @return true|false + * @return bool */ function canEditMetadata($metadata = null, $user_guid = 0) { return can_edit_entity_metadata($this->getGUID(), $user_guid, $metadata); @@ -964,7 +964,7 @@ abstract class ElggEntity extends ElggData implements * * @tip Can be overridden by registering for the permissions_check:comment, * <entity type> plugin hook. - * + * * @param int $user_guid User guid (default is logged in user) * * @return bool @@ -1270,15 +1270,23 @@ abstract class ElggEntity extends ElggData implements public function save() { $guid = $this->getGUID(); if ($guid > 0) { - cache_entity($this); - return update_entity( + // See #5600. This ensures the lower level can_edit_entity() check will use a + // fresh entity from the DB so it sees the persisted owner_guid + _elgg_disable_caching_for_entity($guid); + + $ret = update_entity( $guid, $this->get('owner_guid'), $this->get('access_id'), $this->get('container_guid'), $this->get('time_created') ); + + _elgg_enable_caching_for_entity($guid); + _elgg_cache_entity($this); + + return $ret; } else { // Create a new entity (nb: using attribute array directly // 'cos set function does something special!) @@ -1320,7 +1328,7 @@ abstract class ElggEntity extends ElggData implements $this->attributes['subtype'] = get_subtype_id($this->attributes['type'], $this->attributes['subtype']); - cache_entity($this); + _elgg_cache_entity($this); return $this->attributes['guid']; } @@ -1357,12 +1365,12 @@ abstract class ElggEntity extends ElggData implements $this->attributes['tables_loaded']++; } - // guid needs to be an int http://trac.elgg.org/ticket/4111 + // guid needs to be an int https://github.com/elgg/elgg/issues/4111 $this->attributes['guid'] = (int)$this->attributes['guid']; // Cache object handle if ($this->attributes['guid']) { - cache_entity($this); + _elgg_cache_entity($this); } return true; @@ -1668,9 +1676,11 @@ abstract class ElggEntity extends ElggData implements /** * Import data from an parsed ODD xml data array. * - * @param array $data XML data + * @param ODD $data XML data * * @return true + * + * @throws InvalidParameterException */ public function import(ODD $data) { if (!($data instanceof ODDEntity)) { @@ -1732,8 +1742,6 @@ abstract class ElggEntity extends ElggData implements * @return array */ public function getTags($tag_names = NULL) { - global $CONFIG; - if ($tag_names && !is_array($tag_names)) { $tag_names = array($tag_names); } diff --git a/engine/classes/ElggExtender.php b/engine/classes/ElggExtender.php index d94bad837..25aba354f 100644 --- a/engine/classes/ElggExtender.php +++ b/engine/classes/ElggExtender.php @@ -171,7 +171,7 @@ abstract class ElggExtender extends ElggData { public function export() { $uuid = get_uuid_from_object($this); - $meta = new ODDMetadata($uuid, guid_to_uuid($this->entity_guid), $this->attributes['name'], + $meta = new ODDMetaData($uuid, guid_to_uuid($this->entity_guid), $this->attributes['name'], $this->attributes['value'], $this->attributes['type'], guid_to_uuid($this->owner_guid)); $meta->setAttribute('published', date("r", $this->time_created)); diff --git a/engine/classes/ElggFile.php b/engine/classes/ElggFile.php index f21621ffd..23080834b 100644 --- a/engine/classes/ElggFile.php +++ b/engine/classes/ElggFile.php @@ -93,6 +93,7 @@ class ElggFile extends ElggObject { $container_guid = $this->container_guid; } $fs = $this->getFilestore(); + // @todo add getSize() to ElggFilestore return $fs->getSize($prefix, $container_guid); } @@ -127,9 +128,11 @@ class ElggFile extends ElggObject { * @param mixed $default A default. Useful to pass what the browser thinks it is. * @since 1.7.12 * + * @note If $file is provided, this may be called statically + * * @return mixed Detected type on success, false on failure. */ - static function detectMimeType($file = null, $default = null) { + public function detectMimeType($file = null, $default = null) { if (!$file) { if (isset($this) && $this->filename) { $file = $this->filename; @@ -178,6 +181,8 @@ class ElggFile extends ElggObject { * @param string $mode Either read/write/append * * @return resource File handler + * + * @throws IOException|InvalidParameterException */ public function open($mode) { if (!$this->getFilename()) { @@ -270,9 +275,14 @@ class ElggFile extends ElggObject { */ public function delete() { $fs = $this->getFilestore(); - if ($fs->delete($this)) { - return parent::delete(); + + $result = $fs->delete($this); + + if ($this->getGUID() && $result) { + $result = parent::delete(); } + + return $result; } /** @@ -285,6 +295,7 @@ class ElggFile extends ElggObject { public function seek($position) { $fs = $this->getFilestore(); + // @todo add seek() to ElggFilestore return $fs->seek($this->handle, $position); } @@ -347,6 +358,8 @@ class ElggFile extends ElggObject { * a filestore as recorded in metadata or the system default. * * @return ElggFilestore + * + * @throws ClassNotFoundException */ protected function getFilestore() { // Short circuit if already set. @@ -359,7 +372,6 @@ class ElggFile extends ElggObject { // need to get all filestore::* metadata because the rest are "parameters" that // get passed to filestore::setParameters() if ($this->guid) { - $db_prefix = elgg_get_config('dbprefix'); $options = array( 'guid' => $this->guid, 'where' => array("n.string LIKE 'filestore::%'"), @@ -388,6 +400,7 @@ class ElggFile extends ElggObject { $this->filestore = new $filestore(); $this->filestore->setParameters($parameters); + // @todo explain why $parameters will always be set here (PhpStorm complains) } // this means the entity hasn't been saved so fallback to default diff --git a/engine/classes/ElggFileCache.php b/engine/classes/ElggFileCache.php index 34178d452..94143f777 100644 --- a/engine/classes/ElggFileCache.php +++ b/engine/classes/ElggFileCache.php @@ -13,6 +13,8 @@ class ElggFileCache extends ElggCache { * @param string $cache_path The cache path. * @param int $max_age Maximum age in seconds, 0 if no limit. * @param int $max_size Maximum size of cache in seconds, 0 if no limit. + * + * @throws ConfigurationException */ function __construct($cache_path, $max_age = 0, $max_size = 0) { $this->setVariable("cache_path", $cache_path); @@ -24,6 +26,7 @@ class ElggFileCache extends ElggCache { } } + // @codingStandardsIgnoreStart /** * Create and return a handle to a file. * @@ -39,6 +42,7 @@ class ElggFileCache extends ElggCache { return $this->createFile($filename, $rw); } + // @codingStandardsIgnoreEnd /** * Create and return a handle to a file. @@ -70,6 +74,7 @@ class ElggFileCache extends ElggCache { return fopen($path . $filename, $rw); } + // @codingStandardsIgnoreStart /** * Create a sanitised filename for the file. * @@ -84,6 +89,7 @@ class ElggFileCache extends ElggCache { return $filename; } + // @codingStandardsIgnoreEnd /** * Create a sanitised filename for the file. diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php index ea257f368..7e69b7a84 100644 --- a/engine/classes/ElggGroup.php +++ b/engine/classes/ElggGroup.php @@ -32,7 +32,7 @@ class ElggGroup extends ElggEntity * @param mixed $guid If an int, load that GUID. * If an entity table db row, then will load the rest of the data. * - * @throws Exception if there was a problem creating the group. + * @throws IOException|InvalidParameterException if there was a problem creating the group. */ function __construct($guid = null) { $this->initializeAttributes(); @@ -48,21 +48,18 @@ class ElggGroup extends ElggEntity $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // Is $guid is an ElggGroup? Use a copy constructor } else if ($guid instanceof ElggGroup) { + // $guid is an ElggGroup so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggGroup constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggGroup = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo why separate from else throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggGroup')); - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load entity if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } @@ -220,6 +217,7 @@ class ElggGroup extends ElggEntity * @return array|false */ public function getObjects($subtype = "", $limit = 10, $offset = 0) { + // @todo are we deprecating this method, too? return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", $limit, $offset, false); } @@ -233,6 +231,7 @@ class ElggGroup extends ElggEntity * @return array|false */ public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0) { + // @todo are we deprecating this method, too? return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", $limit, $offset, false); } @@ -244,6 +243,7 @@ class ElggGroup extends ElggEntity * @return array|false */ public function countObjects($subtype = "") { + // @todo are we deprecating this method, too? return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", 10, 0, true); } @@ -284,7 +284,7 @@ class ElggGroup extends ElggEntity * * @return bool */ - public function isMember($user = 0) { + public function isMember($user = null) { if (!($user instanceof ElggUser)) { $user = elgg_get_logged_in_user_entity(); } @@ -335,7 +335,7 @@ class ElggGroup extends ElggEntity $this->attributes = $attrs; $this->attributes['tables_loaded'] = 2; - cache_entity($this); + _elgg_cache_entity($this); return true; } @@ -352,7 +352,12 @@ class ElggGroup extends ElggEntity } // Now save specific stuff - return create_group_entity($this->get('guid'), $this->get('name'), $this->get('description')); + + _elgg_disable_caching_for_entity($this->guid); + $ret = create_group_entity($this->get('guid'), $this->get('name'), $this->get('description')); + _elgg_enable_caching_for_entity($this->guid); + + return $ret; } // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// diff --git a/engine/classes/ElggLRUCache.php b/engine/classes/ElggLRUCache.php new file mode 100644 index 000000000..f51af2ed7 --- /dev/null +++ b/engine/classes/ElggLRUCache.php @@ -0,0 +1,181 @@ +<?php + +/** + * Least Recently Used Cache + * + * A fixed sized cache that removes the element used last when it reaches its + * size limit. + * + * Based on https://github.com/cash/LRUCache + * + * @access private + * + * @package Elgg.Core + * @subpackage Cache + */ +class ElggLRUCache implements ArrayAccess { + /** @var int */ + protected $maximumSize; + + /** + * The front of the array contains the LRU element + * + * @var array + */ + protected $data = array(); + + /** + * Create a LRU Cache + * + * @param int $size The size of the cache + * @throws InvalidArgumentException + */ + public function __construct($size) { + if (!is_int($size) || $size <= 0) { + throw new InvalidArgumentException(); + } + $this->maximumSize = $size; + } + + /** + * Get the value cached with this key + * + * @param int|string $key The key. Strings that are ints are cast to ints. + * @param mixed $default The value to be returned if key not found. (Optional) + * @return mixed + */ + public function get($key, $default = null) { + if (isset($this->data[$key])) { + $this->recordAccess($key); + return $this->data[$key]; + } else { + return $default; + } + } + + /** + * Add something to the cache + * + * @param int|string $key The key. Strings that are ints are cast to ints. + * @param mixed $value The value to cache + * @return void + */ + public function set($key, $value) { + if (isset($this->data[$key])) { + $this->data[$key] = $value; + $this->recordAccess($key); + } else { + $this->data[$key] = $value; + if ($this->size() > $this->maximumSize) { + // remove least recently used element (front of array) + reset($this->data); + unset($this->data[key($this->data)]); + } + } + } + + /** + * Get the number of elements in the cache + * + * @return int + */ + public function size() { + return count($this->data); + } + + /** + * Does the cache contain an element with this key + * + * @param int|string $key The key + * @return boolean + */ + public function containsKey($key) { + return isset($this->data[$key]); + } + + /** + * Remove the element with this key. + * + * @param int|string $key The key + * @return mixed Value or null if not set + */ + public function remove($key) { + if (isset($this->data[$key])) { + $value = $this->data[$key]; + unset($this->data[$key]); + return $value; + } else { + return null; + } + } + + /** + * Clear the cache + * + * @return void + */ + public function clear() { + $this->data = array(); + } + + /** + * Moves the element from current position to end of array + * + * @param int|string $key The key + * @return void + */ + protected function recordAccess($key) { + $value = $this->data[$key]; + unset($this->data[$key]); + $this->data[$key] = $value; + } + + /** + * Assigns a value for the specified key + * + * @see ArrayAccess::offsetSet() + * + * @param int|string $key The key to assign the value to. + * @param mixed $value The value to set. + * @return void + */ + public function offsetSet($key, $value) { + $this->set($key, $value); + } + + /** + * Get the value for specified key + * + * @see ArrayAccess::offsetGet() + * + * @param int|string $key The key to retrieve. + * @return mixed + */ + public function offsetGet($key) { + return $this->get($key); + } + + /** + * Unsets a key. + * + * @see ArrayAccess::offsetUnset() + * + * @param int|string $key The key to unset. + * @return void + */ + public function offsetUnset($key) { + $this->remove($key); + } + + /** + * Does key exist? + * + * @see ArrayAccess::offsetExists() + * + * @param int|string $key A key to check for. + * @return boolean + */ + public function offsetExists($key) { + return $this->containsKey($key); + } +} diff --git a/engine/classes/ElggMemcache.php b/engine/classes/ElggMemcache.php index d9539b9cb..91d50ab89 100644 --- a/engine/classes/ElggMemcache.php +++ b/engine/classes/ElggMemcache.php @@ -32,6 +32,8 @@ class ElggMemcache extends ElggSharedMemoryCache { * * @param string $namespace The namespace for this cache to write to - * note, namespaces of the same name are shared! + * + * @throws ConfigurationException */ function __construct($namespace = 'default') { global $CONFIG; diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php index d9a704dd9..b463143d8 100644 --- a/engine/classes/ElggMenuBuilder.php +++ b/engine/classes/ElggMenuBuilder.php @@ -8,6 +8,9 @@ */ class ElggMenuBuilder { + /** + * @var ElggMenuItem[] + */ protected $menu = array(); protected $selected = null; @@ -15,7 +18,7 @@ class ElggMenuBuilder { /** * ElggMenuBuilder constructor * - * @param array $menu Array of ElggMenuItem objects + * @param ElggMenuItem[] $menu Array of ElggMenuItem objects */ public function __construct(array $menu) { $this->menu = $menu; @@ -107,6 +110,7 @@ class ElggMenuBuilder { $children = array(); // divide base nodes from children foreach ($section as $menu_item) { + /* @var ElggMenuItem $menu_item */ $parent_name = $menu_item->getParentName(); if (!$parent_name) { $parents[$menu_item->getName()] = $menu_item; @@ -118,13 +122,16 @@ class ElggMenuBuilder { // attach children to parents $iteration = 0; $current_gen = $parents; + $next_gen = null; while (count($children) && $iteration < 5) { foreach ($children as $index => $menu_item) { $parent_name = $menu_item->getParentName(); if (array_key_exists($parent_name, $current_gen)) { $next_gen[$menu_item->getName()] = $menu_item; - $current_gen[$parent_name]->addChild($menu_item); - $menu_item->setParent($current_gen[$parent_name]); + if (!in_array($menu_item, $current_gen[$parent_name]->getData('children'))) { + $current_gen[$parent_name]->addChild($menu_item); + $menu_item->setParent($current_gen[$parent_name]); + } unset($children[$index]); } } @@ -216,12 +223,12 @@ class ElggMenuBuilder { array_push($stack, $root); while (!empty($stack)) { $node = array_pop($stack); + /* @var ElggMenuItem $node */ $node->sortChildren($sort_callback); $children = $node->getChildren(); if ($children) { $stack = array_merge($stack, $children); } - $p = count($stack); } } } @@ -230,8 +237,8 @@ class ElggMenuBuilder { /** * Compare two menu items by their display text * - * @param ElggMenuItem $a - * @param ElggMenuItem $b + * @param ElggMenuItem $a Menu item + * @param ElggMenuItem $b Menu item * @return bool */ public static function compareByText($a, $b) { @@ -248,8 +255,8 @@ class ElggMenuBuilder { /** * Compare two menu items by their identifiers * - * @param ElggMenuItem $a - * @param ElggMenuItem $b + * @param ElggMenuItem $a Menu item + * @param ElggMenuItem $b Menu item * @return bool */ public static function compareByName($a, $b) { @@ -266,9 +273,11 @@ class ElggMenuBuilder { /** * Compare two menu items by their priority * - * @param ElggMenuItem $a - * @param ElggMenuItem $b + * @param ElggMenuItem $a Menu item + * @param ElggMenuItem $b Menu item * @return bool + * + * @todo change name to compareByPriority */ public static function compareByWeight($a, $b) { $aw = $a->getWeight(); diff --git a/engine/classes/ElggMetadata.php b/engine/classes/ElggMetadata.php index 7f45dc3ea..3a8e2d817 100644 --- a/engine/classes/ElggMetadata.php +++ b/engine/classes/ElggMetadata.php @@ -6,6 +6,10 @@ * * @package Elgg.Core * @subpackage Metadata + * + * @property string $value_type + * @property int $owner_guid + * @property string $enabled */ class ElggMetadata extends ElggExtender { diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php index 6263f84f6..aeaa3ba5c 100644 --- a/engine/classes/ElggObject.php +++ b/engine/classes/ElggObject.php @@ -66,21 +66,18 @@ class ElggObject extends ElggEntity { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // Is $guid is an ElggObject? Use a copy constructor } else if ($guid instanceof ElggObject) { + // $guid is an ElggObject so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggObject constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggObject = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo remove - do not need separate exception throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggObject')); - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } @@ -110,7 +107,7 @@ class ElggObject extends ElggEntity { $this->attributes = $attrs; $this->attributes['tables_loaded'] = 2; - cache_entity($this); + _elgg_cache_entity($this); return true; } @@ -129,8 +126,12 @@ class ElggObject extends ElggEntity { } // Save ElggObject-specific attributes - return create_object_entity($this->get('guid'), $this->get('title'), - $this->get('description')); + + _elgg_disable_caching_for_entity($this->guid); + $ret = create_object_entity($this->get('guid'), $this->get('title'), $this->get('description')); + _elgg_enable_caching_for_entity($this->guid); + + return $ret; } /** diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index 8f71b79a8..545b9a53c 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -145,7 +145,7 @@ class ElggPlugin extends ElggObject { /** * Sets the location of this plugin. * - * @param path $id The path to the plugin's dir. + * @param string $id The path to the plugin's dir. * @return bool */ public function setID($id) { @@ -299,17 +299,15 @@ class ElggPlugin extends ElggObject { $private_settings = get_data($q); - if ($private_settings) { - $return = array(); + $return = array(); + if ($private_settings) { foreach ($private_settings as $setting) { $return[$setting->name] = $setting->value; } - - return $return; } - return false; + return $return; } /** @@ -350,11 +348,14 @@ class ElggPlugin extends ElggObject { */ public function unsetAllSettings() { $db_prefix = get_config('dbprefix'); - $ps_prefix = elgg_namespace_plugin_private_setting('setting', ''); + + $us_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID()); + $is_prefix = elgg_namespace_plugin_private_setting('internal', '', $this->getID()); $q = "DELETE FROM {$db_prefix}private_settings WHERE entity_guid = $this->guid - AND name NOT LIKE '$ps_prefix%'"; + AND name NOT LIKE '$us_prefix%' + AND name NOT LIKE '$is_prefix%'"; return delete_data($q); } @@ -420,20 +421,18 @@ class ElggPlugin extends ElggObject { $private_settings = get_data($q); - if ($private_settings) { - $return = array(); + $return = array(); + if ($private_settings) { foreach ($private_settings as $setting) { $name = substr($setting->name, $ps_prefix_len); $value = $setting->value; $return[$name] = $value; } - - return $return; } - return false; + return $return; } /** @@ -546,7 +545,7 @@ class ElggPlugin extends ElggObject { * Returns if the plugin is complete, meaning has all required files * and Elgg can read them and they make sense. * - * @todo bad name? This could be confused with isValid() from ElggPackage. + * @todo bad name? This could be confused with isValid() from ElggPluginPackage. * * @return bool */ @@ -597,6 +596,8 @@ class ElggPlugin extends ElggObject { * Checks if this plugin can be activated on the current * Elgg installation. * + * @todo remove $site_guid param or implement it + * * @param mixed $site_guid Optional site guid * @return bool */ @@ -647,8 +648,8 @@ class ElggPlugin extends ElggObject { // Note: this will not run re-run the init hooks! if ($return) { if ($this->canReadFile('activate.php')) { - $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES - | ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS; + $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES | + ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS; $this->start($flags); diff --git a/engine/classes/ElggPluginPackage.php b/engine/classes/ElggPluginPackage.php index 2dc4bdb3d..37eb4bf4d 100644 --- a/engine/classes/ElggPluginPackage.php +++ b/engine/classes/ElggPluginPackage.php @@ -100,7 +100,6 @@ class ElggPluginPackage { * @param string $plugin The ID (directory name) or full path of the plugin. * @param bool $validate Automatically run isValid()? * - * @return true * @throws PluginException */ public function __construct($plugin, $validate = true) { @@ -213,6 +212,7 @@ class ElggPluginPackage { return false; } + // Note: $conflicts and $requires are not unused. They're called dynamically $conflicts = $this->getManifest()->getConflicts(); $requires = $this->getManifest()->getRequires(); $provides = $this->getManifest()->getProvides(); @@ -294,6 +294,7 @@ class ElggPluginPackage { return true; } + $this->errorMsg = elgg_echo('unknown_error'); return false; } @@ -330,8 +331,10 @@ class ElggPluginPackage { * @return bool|array */ public function checkDependencies($full_report = false) { + // Note: $conflicts and $requires are not unused. They're called dynamically $requires = $this->getManifest()->getRequires(); $conflicts = $this->getManifest()->getConflicts(); + $enabled_plugins = elgg_get_plugins('active'); $this_id = $this->getID(); $report = array(); @@ -368,6 +371,7 @@ class ElggPluginPackage { $check_types = array('requires', 'conflicts'); if ($full_report) { + // Note: $suggests is not unused. It's called dynamically $suggests = $this->getManifest()->getSuggests(); $check_types[] = 'suggests'; } diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php index 8a3b836a8..416df885c 100644 --- a/engine/classes/ElggPriorityList.php +++ b/engine/classes/ElggPriorityList.php @@ -89,7 +89,7 @@ * return true; * } * - * @package Elgg.Core + * @package Elgg.Core * @subpackage Helpers */ class ElggPriorityList @@ -126,7 +126,9 @@ class ElggPriorityList * maintains its priority and the new element is to the next available * slot, taking into consideration all previously registered elements. * Negative elements are accepted. + * @param bool $exact unused * @return int The priority of the added element. + * @todo remove $exact or implement it. Note we use variable name strict below. */ public function add($element, $priority = null, $exact = false) { if ($priority !== null && !is_numeric($priority)) { @@ -146,7 +148,8 @@ class ElggPriorityList * @warning The element must have the same attributes / values. If using $strict, it must have * the same types. array(10) will fail in strict against array('10') (str vs int). * - * @param type $element + * @param mixed $element The element to remove from the list + * @param bool $strict Whether to check the type of the element match * @return bool */ public function remove($element, $strict = false) { @@ -162,10 +165,10 @@ class ElggPriorityList /** * Move an existing element to a new priority. * - * @param mixed $current_priority - * @param int $new_priority - * - * @return int The new priority. + * @param mixed $element The element to move + * @param int $new_priority The new priority for the element + * @param bool $strict Whether to check the type of the element match + * @return bool */ public function move($element, $new_priority, $strict = false) { $new_priority = (int) $new_priority; @@ -200,12 +203,12 @@ class ElggPriorityList * * If no user function is provided the elements are sorted by priority registered. * - * The callback function should accept the array of elements as the first argument and should - * return a sorted array. + * The callback function should accept the array of elements as the first + * argument and should return a sorted array. * * This function can be called multiple times. * - * @param type $callback + * @param callback $callback The callback for sorting. Numeric sorting is the default. * @return bool */ public function sort($callback = null) { @@ -268,7 +271,7 @@ class ElggPriorityList /** * Returns the element at $priority. * - * @param int $priority + * @param int $priority The priority * @return mixed The element or false on fail. */ public function getElement($priority) { @@ -351,7 +354,12 @@ class ElggPriorityList return ($key !== NULL && $key !== FALSE); } - // Countable + /** + * Countable interface + * + * @see Countable::count() + * @return int + */ public function count() { return count($this->elements); } diff --git a/engine/classes/ElggRelationship.php b/engine/classes/ElggRelationship.php index efc0f7eff..d2e88882a 100644 --- a/engine/classes/ElggRelationship.php +++ b/engine/classes/ElggRelationship.php @@ -71,6 +71,7 @@ class ElggRelationship extends ElggData implements * Save the relationship * * @return int the relationship id + * @throws IOException */ public function save() { if ($this->id > 0) { @@ -145,7 +146,7 @@ class ElggRelationship extends ElggData implements * @param ODD $data ODD data * @return bool - * @throws ImportException + * @throws ImportException|InvalidParameterException */ public function import(ODD $data) { if (!($data instanceof ODDRelationship)) { @@ -179,6 +180,8 @@ class ElggRelationship extends ElggData implements return true; } } + + return false; } // SYSTEM LOG INTERFACE //////////////////////////////////////////////////////////// diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php index 1fe49b85c..dd996fe98 100644 --- a/engine/classes/ElggSite.php +++ b/engine/classes/ElggSite.php @@ -77,28 +77,24 @@ class ElggSite extends ElggEntity { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // Is $guid is an ElggSite? Use a copy constructor } else if ($guid instanceof ElggSite) { + // $guid is an ElggSite so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggSite constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggSite = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo remove and just use else clause throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggSite')); - - // See if this is a URL } else if (strpos($guid, "http") !== false) { + // url so retrieve by url $guid = get_site_by_url($guid); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } @@ -128,7 +124,7 @@ class ElggSite extends ElggEntity { $this->attributes = $attrs; $this->attributes['tables_loaded'] = 2; - cache_entity($this); + _elgg_cache_entity($this); return true; } @@ -381,7 +377,9 @@ class ElggSite extends ElggEntity { elgg_register_plugin_hook_handler('index', 'system', 'elgg_walled_garden_index', 1); if (!$this->isPublicPage()) { - $_SESSION['last_forward_from'] = current_page_url(); + if (!elgg_is_xhr()) { + $_SESSION['last_forward_from'] = current_page_url(); + } register_error(elgg_echo('loggedinrequired')); forward(); } @@ -443,8 +441,6 @@ class ElggSite extends ElggEntity { // include a hook for plugin authors to include public pages $plugins = elgg_trigger_plugin_hook('public_pages', 'walled_garden', NULL, array()); - // lookup admin-specific public pages - // allow public pages foreach (array_merge($defaults, $plugins) as $public) { $pattern = "`^{$CONFIG->url}$public/*$`i"; diff --git a/engine/classes/ElggStaticVariableCache.php b/engine/classes/ElggStaticVariableCache.php index 17d849400..9c14fdfba 100644 --- a/engine/classes/ElggStaticVariableCache.php +++ b/engine/classes/ElggStaticVariableCache.php @@ -11,7 +11,7 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache { /** * The cache. * - * @var unknown_type + * @var array */ private static $__cache; @@ -22,7 +22,7 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache { * memory, optionally with a given namespace (to avoid overlap). * * @param string $namespace The namespace for this cache to write to. - * @note namespaces of the same name are shared! + * @warning namespaces of the same name are shared! */ function __construct($namespace = 'default') { $this->setNamespace($namespace); @@ -80,7 +80,7 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache { } /** - * This was probably meant to delete everything? + * Clears the cache for a particular namespace * * @return void */ diff --git a/engine/classes/ElggTranslit.php b/engine/classes/ElggTranslit.php index 676c59fc8..b4bf87797 100644 --- a/engine/classes/ElggTranslit.php +++ b/engine/classes/ElggTranslit.php @@ -20,11 +20,10 @@ * and is licensed under the LGPL. For more information, see * <http://www.doctrine-project.org>. * - * @author Konsta Vesterinen <kvesteri@cc.hut.fi> - * @author Jonathan H. Wage <jonwage@gmail.com> - * - * @author Steve Clay <steve@mrclay.org> - * @package Elgg.Core + * @package Elgg.Core + * @author Konsta Vesterinen <kvesteri@cc.hut.fi> + * @author Jonathan H. Wage <jonwage@gmail.com> + * @author Steve Clay <steve@mrclay.org> * * @access private Plugin authors should not use this directly */ @@ -32,8 +31,9 @@ class ElggTranslit { /** * Create a version of a string for embedding in a URL - * @param string $string a UTF-8 string - * @param string $separator + * + * @param string $string A UTF-8 string + * @param string $separator The character to separate words with * @return string */ static public function urlize($string, $separator = '-') { @@ -49,24 +49,29 @@ class ElggTranslit { // Internationalization, AND 日本語! $string = self::transliterateAscii($string); - // more translation + // allow HTML tags in titles + $string = preg_replace('~<([a-zA-Z][^>]*)>~', ' $1 ', $string); + + // more substitutions + // @todo put these somewhere else $string = strtr($string, array( - // Euro/GBP - "\xE2\x82\xAC" /* € */ => 'E', "\xC2\xA3" /* £ */ => 'GBP', + // currency + "\xE2\x82\xAC" /* € */ => ' E ', + "\xC2\xA3" /* £ */ => ' GBP ', )); // remove all ASCII except 0-9a-zA-Z, hyphen, underscore, and whitespace // note: "x" modifier did not work with this pattern. $string = preg_replace('~[' - . '\x00-\x08' # control chars - . '\x0b\x0c' # vert tab, form feed - . '\x0e-\x1f' # control chars - . '\x21-\x2c' # ! ... , - . '\x2e\x2f' # . slash - . '\x3a-\x40' # : ... @ - . '\x5b-\x5e' # [ ... ^ - . '\x60' # ` - . '\x7b-\x7f' # { ... DEL + . '\x00-\x08' // control chars + . '\x0b\x0c' // vert tab, form feed + . '\x0e-\x1f' // control chars + . '\x21-\x2c' // ! ... , + . '\x2e\x2f' // . slash + . '\x3a-\x40' // : ... @ + . '\x5b-\x5e' // [ ... ^ + . '\x60' // ` + . '\x7b-\x7f' // { ... DEL . ']~', '', $string); $string = strtr($string, '', ''); @@ -80,10 +85,10 @@ class ElggTranslit { // note: we cannot use [^0-9a-zA-Z] because that matches multibyte chars. // note: "x" modifier did not work with this pattern. $pattern = '~[' - . '\x00-\x2f' # controls ... slash - . '\x3a-\x40' # : ... @ - . '\x5b-\x60' # [ ... ` - . '\x7b-\x7f' # { ... DEL + . '\x00-\x2f' // controls ... slash + . '\x3a-\x40' // : ... @ + . '\x5b-\x60' // [ ... ` + . '\x7b-\x7f' // { ... DEL . ']+~x'; // ['internationalization', 'and', '日本語'] @@ -98,6 +103,7 @@ class ElggTranslit { /** * Transliterate Western multibyte chars to ASCII + * * @param string $utf8 a UTF-8 string * @return string */ @@ -247,6 +253,7 @@ class ElggTranslit { /** * Tests that "normalizer_normalize" exists and works + * * @return bool */ static public function hasNormalizerSupport() { @@ -255,7 +262,7 @@ class ElggTranslit { $form_c = "\xC3\x85"; // 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5) $form_d = "A\xCC\x8A"; // A followed by 'COMBINING RING ABOVE' (U+030A) $ret = (function_exists('normalizer_normalize') - && $form_c === normalizer_normalize($form_d)); + && $form_c === normalizer_normalize($form_d)); } return $ret; } diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php index 6c1cdc1de..6163f9b62 100644 --- a/engine/classes/ElggUser.php +++ b/engine/classes/ElggUser.php @@ -40,6 +40,9 @@ class ElggUser extends ElggEntity $this->attributes['code'] = NULL; $this->attributes['banned'] = "no"; $this->attributes['admin'] = 'no'; + $this->attributes['prev_last_action'] = NULL; + $this->attributes['last_login'] = NULL; + $this->attributes['prev_last_login'] = NULL; $this->attributes['tables_split'] = 2; } @@ -65,30 +68,26 @@ class ElggUser extends ElggEntity $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // See if this is a username } else if (is_string($guid)) { + // $guid is a username $user = get_user_by_username($guid); if ($user) { foreach ($user->attributes as $key => $value) { $this->attributes[$key] = $value; } } - - // Is $guid is an ElggUser? Use a copy constructor } else if ($guid instanceof ElggUser) { + // $guid is an ElggUser so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggUser constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggUser = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo why have a special case here throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggUser')); - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load entity if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } @@ -116,7 +115,7 @@ class ElggUser extends ElggEntity $this->attributes = $attrs; $this->attributes['tables_loaded'] = 2; - cache_entity($this); + _elgg_cache_entity($this); return true; } @@ -133,9 +132,13 @@ class ElggUser extends ElggEntity } // Now save specific stuff - return create_user_entity($this->get('guid'), $this->get('name'), $this->get('username'), + _elgg_disable_caching_for_entity($this->guid); + $ret = create_user_entity($this->get('guid'), $this->get('name'), $this->get('username'), $this->get('password'), $this->get('salt'), $this->get('email'), $this->get('language'), $this->get('code')); + _elgg_enable_caching_for_entity($this->guid); + + return $ret; } /** diff --git a/engine/classes/ElggVolatileMetadataCache.php b/engine/classes/ElggVolatileMetadataCache.php index 8a33c198d..4acda7cee 100644 --- a/engine/classes/ElggVolatileMetadataCache.php +++ b/engine/classes/ElggVolatileMetadataCache.php @@ -33,9 +33,11 @@ class ElggVolatileMetadataCache { protected $ignoreAccess = null; /** - * @param int $entity_guid - * - * @param array $values + * Cache metadata for an entity + * + * @param int $entity_guid The GUID of the entity + * @param array $values The metadata values to cache + * @return void */ public function saveAll($entity_guid, array $values) { if (!$this->getIgnoreAccess()) { @@ -45,8 +47,9 @@ class ElggVolatileMetadataCache { } /** - * @param int $entity_guid - * + * Get the metadata for an entity + * + * @param int $entity_guid The GUID of the entity * @return array */ public function loadAll($entity_guid) { @@ -61,15 +64,17 @@ class ElggVolatileMetadataCache { * Declare that there may be fetch-able metadata names in storage that this * cache doesn't know about * - * @param int $entity_guid + * @param int $entity_guid The GUID of the entity + * @return void */ public function markOutOfSync($entity_guid) { unset($this->isSynchronized[$entity_guid]); } /** - * @param $entity_guid - * + * Have all the metadata for this entity been cached? + * + * @param int $entity_guid The GUID of the entity * @return bool */ public function isSynchronized($entity_guid) { @@ -77,13 +82,15 @@ class ElggVolatileMetadataCache { } /** - * @param int $entity_guid - * - * @param string $name - * - * @param array|int|string|null $value null means it is known that there is no - * fetch-able metadata under this name - * @param bool $allow_multiple + * Cache a piece of metadata + * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name + * @param array|int|string|null $value The metadata value. null means it is + * known that there is no fetch-able + * metadata under this name + * @param bool $allow_multiple Can the metadata be an array + * @return void */ public function save($entity_guid, $name, $value, $allow_multiple = false) { if ($this->getIgnoreAccess()) { @@ -115,10 +122,8 @@ class ElggVolatileMetadataCache { * function's return value should be trusted (otherwise a null return value * is ambiguous). * - * @param int $entity_guid - * - * @param string $name - * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name * @return array|string|int|null null = value does not exist */ public function load($entity_guid, $name) { @@ -133,9 +138,9 @@ class ElggVolatileMetadataCache { * Forget about this metadata entry. We don't want to try to guess what the * next fetch from storage will return * - * @param int $entity_guid - * - * @param string $name + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name + * @return void */ public function markUnknown($entity_guid, $name) { unset($this->values[$entity_guid][$name]); @@ -145,10 +150,8 @@ class ElggVolatileMetadataCache { /** * If true, load() will return an accurate value for this name * - * @param int $entity_guid - * - * @param string $name - * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name * @return bool */ public function isKnown($entity_guid, $name) { @@ -163,10 +166,8 @@ class ElggVolatileMetadataCache { /** * Declare that metadata under this name is known to be not fetch-able from storage * - * @param int $entity_guid - * - * @param string $name - * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name * @return array */ public function markEmpty($entity_guid, $name) { @@ -176,7 +177,8 @@ class ElggVolatileMetadataCache { /** * Forget about all metadata for an entity * - * @param int $entity_guid + * @param int $entity_guid The GUID of the entity + * @return void */ public function clear($entity_guid) { $this->values[$entity_guid] = array(); @@ -185,6 +187,8 @@ class ElggVolatileMetadataCache { /** * Clear entire cache and mark all entities as out of sync + * + * @return void */ public function flush() { $this->values = array(); @@ -197,7 +201,8 @@ class ElggVolatileMetadataCache { * * This setting makes this component a little more loosely-coupled. * - * @param bool $ignore + * @param bool $ignore Whether to ignore access or not + * @return void */ public function setIgnoreAccess($ignore) { $this->ignoreAccess = (bool) $ignore; @@ -205,12 +210,16 @@ class ElggVolatileMetadataCache { /** * Tell the cache to call elgg_get_ignore_access() to determing access status. + * + * @return void */ public function unsetIgnoreAccess() { $this->ignoreAccess = null; } /** + * Get the ignore access value + * * @return bool */ protected function getIgnoreAccess() { @@ -225,12 +234,10 @@ class ElggVolatileMetadataCache { * Invalidate based on options passed to the global *_metadata functions * * @param string $action Action performed on metadata. "delete", "disable", or "enable" - * - * @param array $options Options passed to elgg_(delete|disable|enable)_metadata - * - * "guid" if given, invalidation will be limited to this entity - * - * "metadata_name" if given, invalidation will be limited to metadata with this name + * @param array $options Options passed to elgg_(delete|disable|enable)_metadata + * "guid" if given, invalidation will be limited to this entity + * "metadata_name" if given, invalidation will be limited to metadata with this name + * @return void */ public function invalidateByOptions($action, array $options) { // remove as little as possible, optimizing for common cases @@ -254,7 +261,10 @@ class ElggVolatileMetadataCache { } /** - * @param int|array $guids + * Populate the cache from a set of entities + * + * @param int|array $guids Array of or single GUIDs + * @return void */ public function populateFromEntities($guids) { if (empty($guids)) { @@ -318,9 +328,7 @@ class ElggVolatileMetadataCache { * cache if RAM usage becomes an issue. * * @param array $guids GUIDs of entities to examine - * - * @param int $limit Limit in characters of all metadata (with ints casted to strings) - * + * @param int $limit Limit in characters of all metadata (with ints casted to strings) * @return array */ public function filterMetadataHeavyEntities(array $guids, $limit = 1024000) { diff --git a/engine/classes/ElggWidget.php b/engine/classes/ElggWidget.php index 99708f66a..66191bf47 100644 --- a/engine/classes/ElggWidget.php +++ b/engine/classes/ElggWidget.php @@ -7,6 +7,11 @@ * * @package Elgg.Core * @subpackage Widgets + * + * @property-read string $handler internal, do not use + * @property-read string $column internal, do not use + * @property-read string $order internal, do not use + * @property-read string $context internal, do not use */ class ElggWidget extends ElggObject { @@ -141,10 +146,15 @@ class ElggWidget extends ElggObject { } } + $bottom_rank = count($widgets); + if ($column == $this->column) { + $bottom_rank--; + } + if ($rank == 0) { // top of the column $this->order = reset($widgets)->order - 10; - } elseif ($rank == (count($widgets) - 1)) { + } elseif ($rank == $bottom_rank) { // bottom of the column of active widgets $this->order = end($widgets)->order + 10; } else { diff --git a/engine/classes/ElggXMLElement.php b/engine/classes/ElggXMLElement.php index 65a13912c..cbd3fc5ce 100644 --- a/engine/classes/ElggXMLElement.php +++ b/engine/classes/ElggXMLElement.php @@ -20,7 +20,12 @@ class ElggXMLElement { if ($xml instanceof SimpleXMLElement) { $this->_element = $xml; } else { + // do not load entities + $disable_load_entities = libxml_disable_entity_loader(true); + $this->_element = new SimpleXMLElement($xml); + + libxml_disable_entity_loader($disable_load_entities); } } @@ -32,7 +37,7 @@ class ElggXMLElement { } /** - * @return array:string The attributes + * @return string[] The attributes */ public function getAttributes() { //include namespace declarations as attributes @@ -64,7 +69,7 @@ class ElggXMLElement { } /** - * @return array:ElggXMLElement Child elements + * @return ElggXMLElement[] Child elements */ public function getChildren() { $children = $this->_element->children(); @@ -76,6 +81,12 @@ class ElggXMLElement { return $result; } + /** + * Override -> + * + * @param string $name Property name + * @return mixed + */ function __get($name) { switch ($name) { case 'name': @@ -94,6 +105,12 @@ class ElggXMLElement { return null; } + /** + * Override isset + * + * @param string $name Property name + * @return boolean + */ function __isset($name) { switch ($name) { case 'name': @@ -111,5 +128,4 @@ class ElggXMLElement { } return false; } - -}
\ No newline at end of file +} diff --git a/engine/classes/ODDMetaData.php b/engine/classes/ODDMetaData.php index 58862e0fb..09b653582 100644 --- a/engine/classes/ODDMetaData.php +++ b/engine/classes/ODDMetaData.php @@ -10,12 +10,12 @@ class ODDMetaData extends ODD { /** * New ODD metadata * - * @param unknown_type $uuid Unique ID - * @param unknown_type $entity_uuid Another unique ID - * @param unknown_type $name Name - * @param unknown_type $value Value - * @param unknown_type $type Type - * @param unknown_type $owner_uuid Owner ID + * @param string $uuid Unique ID + * @param string $entity_uuid Another unique ID + * @param string $name Name + * @param string $value Value + * @param string $type Type + * @param string $owner_uuid Owner ID */ function __construct($uuid, $entity_uuid, $name, $value, $type = "", $owner_uuid = "") { parent::__construct(); @@ -31,7 +31,7 @@ class ODDMetaData extends ODD { /** * Returns 'metadata' * - * @return 'metadata' + * @return string 'metadata' */ protected function getTagName() { return "metadata"; diff --git a/engine/classes/ODDRelationship.php b/engine/classes/ODDRelationship.php index 2906b1c73..8b1fe217b 100644 --- a/engine/classes/ODDRelationship.php +++ b/engine/classes/ODDRelationship.php @@ -10,9 +10,9 @@ class ODDRelationship extends ODD { /** * New ODD Relationship * - * @param unknown_type $uuid1 First UUID - * @param unknown_type $type Type of telationship - * @param unknown_type $uuid2 Second UUId + * @param string $uuid1 First UUID + * @param string $type Type of telationship + * @param string $uuid2 Second UUId */ function __construct($uuid1, $type, $uuid2) { parent::__construct(); @@ -25,7 +25,7 @@ class ODDRelationship extends ODD { /** * Returns 'relationship' * - * @return 'relationship' + * @return string 'relationship' */ protected function getTagName() { return "relationship"; |