aboutsummaryrefslogtreecommitdiff
path: root/engine/classes
diff options
context:
space:
mode:
Diffstat (limited to 'engine/classes')
-rw-r--r--engine/classes/ElggAccess.php4
-rw-r--r--engine/classes/ElggAnnotation.php5
-rw-r--r--engine/classes/ElggAttributeLoader.php77
-rw-r--r--engine/classes/ElggAutoP.php59
-rw-r--r--engine/classes/ElggBatch.php71
-rw-r--r--engine/classes/ElggCache.php4
-rw-r--r--engine/classes/ElggCrypto.php208
-rw-r--r--engine/classes/ElggData.php20
-rw-r--r--engine/classes/ElggDiskFilestore.php40
-rw-r--r--engine/classes/ElggEntity.php46
-rw-r--r--engine/classes/ElggExtender.php2
-rw-r--r--engine/classes/ElggFile.php21
-rw-r--r--engine/classes/ElggFileCache.php6
-rw-r--r--engine/classes/ElggGroup.php25
-rw-r--r--engine/classes/ElggLRUCache.php181
-rw-r--r--engine/classes/ElggMemcache.php2
-rw-r--r--engine/classes/ElggMenuBuilder.php29
-rw-r--r--engine/classes/ElggMetadata.php4
-rw-r--r--engine/classes/ElggObject.php19
-rw-r--r--engine/classes/ElggPlugin.php33
-rw-r--r--engine/classes/ElggPluginPackage.php6
-rw-r--r--engine/classes/ElggPriorityList.php30
-rw-r--r--engine/classes/ElggRelationship.php5
-rw-r--r--engine/classes/ElggSite.php20
-rw-r--r--engine/classes/ElggStaticVariableCache.php6
-rw-r--r--engine/classes/ElggTranslit.php55
-rw-r--r--engine/classes/ElggUser.php23
-rw-r--r--engine/classes/ElggVolatileMetadataCache.php92
-rw-r--r--engine/classes/ElggWidget.php12
-rw-r--r--engine/classes/ElggXMLElement.php24
-rw-r--r--engine/classes/ODDMetaData.php14
-rw-r--r--engine/classes/ODDRelationship.php8
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";