diff --git a/fp-includes/core/core.bplustree.class.php b/fp-includes/core/core.bplustree.class.php index dfc9779..c8c2b67 100755 --- a/fp-includes/core/core.bplustree.class.php +++ b/fp-includes/core/core.bplustree.class.php @@ -8,16 +8,16 @@ * (c)2008 E.Vacchi * Based on the original work by Aaron Watters (bplustree.py) * - * Classes: + * Classes: * * - BPlustTree - * Mapping keys, integers + * Mapping keys, integers * * - caching_BPT - * Subclass of BPlusTree, caching - * key,value pairs - * read-only: create using BPlusTree, read - * using caching_BPT + * Subclass of BPlusTree, caching + * key,value pairs + * read-only: create using BPlusTree, read + * using caching_BPT * * * Usage @@ -37,7 +37,7 @@ * # read-only * $f = open('myfile', 'r'); * $o = caching_BPT($f); - * + * * $o->open(); * echo $o->getitem('my-key'); * @@ -54,12 +54,12 @@ * ================= * * $walker = $tree->walker( - * string $key_lower, bool $include_lower, - * string $key_upper, bool $include_upper); + * string $key_lower, bool $include_lower, + * string $key_upper, bool $include_upper); * while ($walker->valid) { - * echo $walker->current_key(), - * $walker->current_value(); - * $walker->next(); + * echo $walker->current_key(), + * $walker->current_value(); + * $walker->next(); * } * $walker->first(); #resets internal pointer * @@ -67,7 +67,7 @@ * Internal FIFO * ============= * - * $tree->enable_fifo(); + * $tree->enable_fifo(); * do_some_processing(); * $tree->disable_fifo(); * @@ -75,7 +75,7 @@ * when key accesses are localized. Don't use it in walking * (no need for it) or for single write operations. * - * enable_fifo() takes an optional parameter $length + * enable_fifo() takes an optional parameter $length * (defaults to 33) remember that larger fifos will consume * more memory. * @@ -93,125 +93,139 @@ * * In this case, you just have to define somewhere in your code * - * define('BPT_SORT', SORT_DESC); + * define('BPT_SORT', SORT_DESC); * * and the include the library. - * + * * This somehow weird approach should however make the computation * slightly faster: the setting is evaluated only once, - * when including the library; the compare routine is then defined + * when including the library; the compare routine is then defined * accordingly, and never checked again; otherwise the compare * routine would have to check the setting each time it's called. * - */ - - + */ function d($s) { - return; // disable debug output - if (is_array($s)) { $s = '{ '.implode(", ", $s) . ' }'; } - + return; // disable debug output + if (is_array($s)) { + $s = '{ ' . implode(", ", $s) . ' }'; + } + $x = debug_backtrace(); - $f = @$x[1]['function']; - $l = $x[0]['line']; - + $f = @$x [1] ['function']; + $l = $x [0] ['line']; + echo "[{$f}:{$l}]\t", $s, "\n"; - #echo "---[{$x[2]['function']}:{$x[2]['line']}]\n"; + // echo "---[{$x[2]['function']}:{$x[2]['line']}]\n"; } error_reporting(E_ALL); - if (!defined('BPT_SORT')) { -/** - * @const int type of sorting, defaults to SORT_ASC (ascending); - * SORT_DESC (descending) is also possibile - */ -define('BPT_SORT', SORT_ASC); + /** + * + * @const int type of sorting, defaults to SORT_ASC (ascending); + * SORT_DESC (descending) is also possibile + */ + define('BPT_SORT', SORT_ASC); } - /** + * * @const int no room error */ define('NOROOMERROR', -100); /** + * * @const int null node */ define('BPT_NULL', 0); /** + * * @const int null seek position */ define('BPT_NULLSEEK', 0); /** + * * @const string magic string for bplustree */ define('BPT_VERSION_MAGIC', 'BPT01'); - -#define('BPT_INT_SIZE', 4); - +// define('BPT_INT_SIZE', 4); /** + * * @const int root bit flag */ define('BPT_FLAG_ROOT_BIT', 1); /** - * @const int interior node flag + * + * @const int interior node flag */ define('BPT_FLAG_INTERIOR', 2); /** + * * @const int root flag, shorthand for BPT_FLAG_ROOT_BIT | BPT_FLAG_INTERIOR */ define('BPT_FLAG_ROOT', BPT_FLAG_ROOT_BIT | BPT_FLAG_INTERIOR); /** + * * @const int free node flag */ define('BPT_FLAG_FREE', 4); /** + * * @const int leaf flag */ define('BPT_FLAG_LEAF', 8); /** + * * @const int leaf+root flag, shorthand for BPT_FLAG_ROOT_BIT | BPT_FLAG_LEAF */ -define('BPT_FLAG_LEAFANDROOT', BPT_FLAG_ROOT_BIT | BPT_FLAG_LEAF); +define('BPT_FLAG_LEAFANDROOT', BPT_FLAG_ROOT_BIT | BPT_FLAG_LEAF); /** - * Abstraction for array of pairs + * Abstraction for array of pairs * (meaning with "pair" an array containing two elements) * works only read-only - * */ class pairs { + /** + * * @var array of the first elements of each pair (private) - * + * */ - var $a; + var $a; + /** + * * @var array of the second elements of each pair (private) - * + * */ - var $b; + var $b; + /** - * @var integer current size of the array of pairs * + * @var integer current size of the array of pairs + * */ var $count; - + /* * Constructor * @param array $a array of the first elements of each pair * @parma array $b array of the second elements of each pair * */ - function __construct($a, $b) { - if (($v=count($a))!=count($b)) + function __construct($a, $b) { + if (($v = count($a)) != count($b)) trigger_error("Size of params must match", E_USER_ERROR); - $this->a=$a; $this->b=$b; + $this->a = $a; + $this->b = $b; $this->count = $v; } + /* * returns a slice of the current Couplets object as a new Couplets object * (works like array_slice()) @@ -221,184 +235,214 @@ class pairs { * @returns pairs object * */ - function &slice($offset, $count=null) { - if (is_null($count)) $count = $this->count; - - $a = new pairs( - array_slice($this->a, $offset, $count), - array_slice($this->b, $offset, $count) - ); - + function &slice($offset, $count = null) { + if (is_null($count)) + $count = $this->count; + + $a = new pairs(array_slice($this->a, $offset, $count), array_slice($this->b, $offset, $count)); + return $a; } + /** * inserts a pair ($a, $b) at the offset $offset eventually * pushing other elements to the right - * @param int $offset offset at which insert - * @param mixed $a first element in the pair - * @param mixed $b second element in the pair + * + * @param int $offset + * offset at which insert + * @param mixed $a + * first element in the pair + * @param mixed $b + * second element in the pair */ function insert($offset, $a, $b) { array_splice($this->a, $offset, 0, $a); array_splice($this->b, $offset, 0, $b); $this->count++; } + /** * inserts a pair ($a, $b) in the sub-array of pairs * between $lo and $hi, assuming the array is ordered, - * comparing only the first elements of each pair + * comparing only the first elements of each pair * (assumes there aren't duplicates) * uses {@link BPT_keycmp} for comparing * - * @param mixed $a first element of the pair - * @param mixed $b second element of the pair - * @param int $lo starting offset of the sub-array - * @param int|nul $hi ending offset of the sub-array + * @param mixed $a + * first element of the pair + * @param mixed $b + * second element of the pair + * @param int $lo + * starting offset of the sub-array + * @param int|nul $hi + * ending offset of the sub-array */ - function insort($a, $b, $lo=0, $hi=null) { - if (is_null($hi)) $hi=$this->count; + function insort($a, $b, $lo = 0, $hi = null) { + if (is_null($hi)) + $hi = $this->count; $A = $this->a; $X = $a; - while($lo<$hi) { - $mid = (int)(($lo+$hi)/2); - if (BPT_keycmp($X,$A[$mid])<0) $hi=$mid; - else $lo=$mid+1; + while ($lo < $hi) { + $mid = (int) (($lo + $hi) / 2); + if (BPT_keycmp($X, $A [$mid]) < 0) + $hi = $mid; + else + $lo = $mid + 1; } $this->insert($lo, $a, $b); } + /** * removes the pair at the offset $offset - * @param int $offset offset of the pair targeted for deletion - */ - + * + * @param int $offset + * offset of the pair targeted for deletion + */ function remove($offset) { array_splice($this->a, $offset, 1); array_splice($this->b, $offset, 1); $this->count--; } + /** * append at the end of the current object the contents * of another pairs object * - * @param pairs $pairs a pair object of which the contents - * will be appended to this + * @param pairs $pairs + * a pair object of which the contents + * will be appended to this */ function append(&$pairs) { array_splice($this->a, $this->count, 0, $pairs->a); array_splice($this->b, $this->count, 0, $pairs->b); - $this->count+=$pairs->count; + $this->count += $pairs->count; } + /** * make the object fields read-only */ - function __set($x,$y) { + function __set($x, $y) { trigger_error("Can't edit pairs directly'", E_USER_ERROR); } - + } - if (BPT_SORT == SORT_ASC) { -/** - * compares key $a and $b using a less-than or greather-than relation - * depending on {@link BPT_SORT} constants - * - * the function is very simple, returns strcmp($a,$b) or -strcmp($a,$b) - * depending on the BPT_SORT constant: to be a little bit faster, no check is done - * by the function itself; instead it is defined at load time, depending - * on the value of the BPT_SORT constant - * - */ -function BPT_keycmp($a,$b) { return strcmp($a,$b); } + + /** + * compares key $a and $b using a less-than or greather-than relation + * depending on {@link BPT_SORT} constants + * + * the function is very simple, returns strcmp($a,$b) or -strcmp($a,$b) + * depending on the BPT_SORT constant: to be a little bit faster, no check is done + * by the function itself; instead it is defined at load time, depending + * on the value of the BPT_SORT constant + */ + function BPT_keycmp($a, $b) { + return strcmp($a, $b); + } } else { -function BPT_keycmp($a,$b) { return -strcmp($a,$b); } + + function BPT_keycmp($a, $b) { + return -strcmp($a, $b); + } } /* -function _BPT_bisect($a, $x, $lo=0, $hi=null) { - if (is_null($hi)) - $hi=count($a); - while($lo<$hi && $a[$lo++]<$x) ; - return $lo; -} + * function _BPT_bisect($a, $x, $lo=0, $hi=null) { + * if (is_null($hi)) + * $hi=count($a); + * while($lo<$hi && $a[$lo++]<$x) ; + * return $lo; + * } */ /** * locate an element $x or the nearest bigger one * in the array $a, starting from offset $lo - * and limiting to offset $hi, assuming that $a is + * and limiting to offset $hi, assuming that $a is * ordered by the relation BPT_keycmp - * - * @param mixed $a source array - * @param mixed $x element to find - * @param int $lo leftmost offset - * @param int|null $hi rightmost offset * + * @param mixed $a + * source array + * @param mixed $x + * element to find + * @param int $lo + * leftmost offset + * @param int|null $hi + * rightmost offset + * * @returns integer * */ - -function BPT_bisect($a, $x, $lo=0, $hi=null) { +function BPT_bisect($a, $x, $lo = 0, $hi = null) { if (is_null($hi)) { $hi = count($a); } while ($lo < $hi) { - $mid = (int)(($lo+$hi)/2); - #if ($x < $a[$mid]) - if (BPT_keycmp($x,$a[$mid])<0) + $mid = (int) (($lo + $hi) / 2); + // if ($x < $a[$mid]) + if (BPT_keycmp($x, $a [$mid]) < 0) $hi = $mid; else - $lo = $mid+1; + $lo = $mid + 1; } return $lo; } /* -function BPT_insort(&$a, $x, $lo=0, $hi=null) { - if (is_null($hi)) - $hi = count($a); - while ($lo<$hi) { - $mid = (int) (($lo+$hi)/2); - if ($x < $a[$mid]) - $hi = $mid; - else - $lo = $mid+1; - } - array_splice($a, $lo, 0, array($x)); -} -*/ + * function BPT_insort(&$a, $x, $lo=0, $hi=null) { + * if (is_null($hi)) + * $hi = count($a); + * while ($lo<$hi) { + * $mid = (int) (($lo+$hi)/2); + * if ($x < $a[$mid]) + * $hi = $mid; + * else + * $lo = $mid+1; + * } + * array_splice($a, $lo, 0, array($x)); + * } + */ /* * fifo of bplustree nodes */ class BPlusTree_Node_Fifo { + /** + * * @var array array of elements */ var $fifo = array(); + /** + * * @var array dictionary (associative array) of elements */ var $fifo_dict = array(); + /** * var int size of the fifo */ var $size; - + /** * constructor - * @param int $size specifies size (defaults to 30) + * + * @param int $size + * specifies size (defaults to 30) */ - function __construct($size=30) { - $this->fifosize=$size; + function __construct($size = 30) { + $this->fifosize = $size; } /** * flushes all of the contents of the fifo * to disk */ - function flush_fifo(){ + function flush_fifo() { reset($this->fifo); - while(list(,$node)=each($this->fifo)){ + while ($node = array_shift($this->fifo)) { if ($node->dirty) { $node->store(1); } @@ -406,270 +450,276 @@ class BPlusTree_Node_Fifo { $this->fifo = array(); $this->fifo_dict = array(); } + } /** * defines structure and methods of the node * of a bplustree */ - class BPlusTree_Node { - + /** - * @var integer flags (defined as BPT_* constants) - * specifying the nature of the node (leaf, interior, and combos) * + * @var integer flags (defined as BPT_* constants) + * specifying the nature of the node (leaf, interior, and combos) + * */ var $flag; - /** - * @var integer number of child elements (or values, if a leaf) - * - */ - var $size; + /** - * @var int seek position in the file * + * @var integer number of child elements (or values, if a leaf) + * + */ + var $size; + + /** + * + * @var int seek position in the file + * */ var $position; + /** - * @var resource stream where to output the data - * (typically a file open with fopen()) + * + * @var resource stream where to output the data + * (typically a file open with fopen()) */ - var $infile; + var $infile; + /** + * * @var int maximum lenght of a string key */ - var $keylen; + var $keylen; + /** + * * @var array array of strings, containing keys, of size $size */ var $keys; - /** - * @var array array of longs, of size $size+1 - * if leaf, elements in [0,$size] are the values of each key in $keys: - * at offset $size - ($size+1)-th element - there's the seek - * position of the next leaf (or BPT_NULLSEEK if rightmost leaf) - * - * if interior, - * - * - offset 0 points to the child node where keys are - * are all LESS than those in this node (actually, to $keys[0]), - * - * - offset 1 points to the child node where keys are GREATER or EQUAL to $keys[0] - * but LESS than $keys[1], - * - * - offset 2 points to the child node where keys are >= $keys[1] but < $keys[2], etc... - * - * - * with LESS, GREATER we always mean by the relation {@link BPT_keycmp} - * - * - */ - var $indices; - /** - * @var bool controls deferred writes (using fifo) - * - */ - var $dirty= false; /** + * + * @var array array of longs, of size $size+1 + * if leaf, elements in [0,$size] are the values of each key in $keys: + * at offset $size - ($size+1)-th element - there's the seek + * position of the next leaf (or BPT_NULLSEEK if rightmost leaf) + * + * if interior, + * + * - offset 0 points to the child node where keys are + * are all LESS than those in this node (actually, to $keys[0]), + * + * - offset 1 points to the child node where keys are GREATER or EQUAL to $keys[0] + * but LESS than $keys[1], + * + * - offset 2 points to the child node where keys are >= $keys[1] but < $keys[2], etc... + * + * + * with LESS, GREATER we always mean by the relation {@link BPT_keycmp} + * + * + */ + var $indices; + + /** + * + * @var bool controls deferred writes (using fifo) + * + */ + var $dirty = false; + + /** + * * @var BPlusTree_Node_Fifo object of type {@link BPlusTree_Node_Fifo} */ var $fifo = null; + /** + * * @var int number of valid keys in $keys */ var $validkeys; - /** * constructor - * @param int $flag flag of current node - * @param int $size size of node - * @param int $keylen max key length - * @param long $position seek position in file - * @param resource resource stream (opened file) - * @param BPlusTree_Node object from which cloning properties + * + * @param int $flag + * flag of current node + * @param int $size + * size of node + * @param int $keylen + * max key length + * @param long $position + * seek position in file + * @param + * resource resource stream (opened file) + * @param + * BPlusTree_Node object from which cloning properties */ - function __construct($flag, - $size, - $keylen, - $position, - $infile, - $cloner = null) { - + function __construct($flag, $size, $keylen, $position, $infile, $cloner = null) { $this->flag = $flag; - + if ($size < 0) { trigger_error('size must be positive', E_USER_ERROR); } - + $this->size = $size; - + $this->keylen = $keylen; $this->position = $position; $this->infile = $infile; // last (+1) is successor seek TODO move to its own! - $this->indices = array_fill(0, $size+1, BPT_NULL); + $this->indices = array_fill(0, $size + 1, BPT_NULL); $this->keys = array_fill(0, $size, ''); if (is_null($cloner)) { $this->storage = 2 + /* 2 chars for flag, validkeys */ - $size*4+4 + /* n 4B-long indices + 1 4B-long next pointer*/ - $size*$keylen ; /* n keylen-bytes long keys */ + $size * 4 + 4 + /* n 4B-long indices + 1 4B-long next pointer*/ + $size * $keylen; /* n keylen-bytes long keys */ } else { - $this->storage = $cloner->storage; - $this->fifo = $cloner->fifo; + $this->storage = $cloner->storage; + $this->fifo = $cloner->fifo; } - + if ($flag == BPT_FLAG_INTERIOR || $flag == BPT_FLAG_ROOT) { $this->validkeys = -1; } else { $this->validkeys = 0; } - } - /** - * + /** * reinitialize keys - * */ - function clear() { $size = $this->size; // re-init keys - + $this->keys = array_fill(0, $size, ''); $this->validkeys = 0; if (($this->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { // re-init all indices - $this->indices = array_fill(0, $size+1, BPT_NULL); + $this->indices = array_fill(0, $size + 1, BPT_NULL); $this->validkeys = -1; } else { - $fwd = $this->indices[$size]; // forward pointer + $fwd = $this->indices [$size]; // forward pointer $this->indices = array_fill(0, $size, BPT_NULL); $this->keys = array_fill(0, $size, ''); - $this->indices[] = $fwd; + $this->indices [] = $fwd; } } - + /** * returns clone of the obect at position $position - * @param long $position seek position + * + * @param long $position + * seek position */ function &getclone($position) { - if ($this->fifo) { - $dict =& $this->fifo->fifo_dict; - if (isset($dict[$position])) { - return $dict[$position]; + $dict = & $this->fifo->fifo_dict; + if (isset($dict [$position])) { + return $dict [$position]; } } - - $o = new BPlusTree_Node( - $this->flag, - $this->size, - $this->keylen, - $position, - $this->infile, - $this - ); + $o = new BPlusTree_Node($this->flag, $this->size, $this->keylen, $position, $this->infile, $this); return $o; } - - /** + + /** * put first index (seek position for less-than child) * - * @param int $index seek position + * @param int $index + * seek position */ function putfirstindex($index) { - if ($this->validkeys>=0) + if ($this->validkeys >= 0) trigger_error("Can't putfirstindex on full node", E_USER_ERROR); - $this->indices[0] = $index; + $this->indices [0] = $index; $this->validkeys = 0; } - /** - * links node $node to this node as a child, using key $key - * (this node must be interior) - * - * @param string $key key string - * @param object $node node to link - * - */ + /** + * links node $node to this node as a child, using key $key + * (this node must be interior) + * + * @param string $key + * key string + * @param object $node + * node to link + * + */ function putnode($key, &$node) { $position = $node->position; return $this->putposition($key, $position); - # if ($x == NOROOMERROR) {print_r(debug_backtrace());fail();} + // if ($x == NOROOMERROR) {print_r(debug_backtrace());fail();} } - + /* - * + * * links a seek position $position to the key $key - * + * * @param string $key key string * @param int $position seek position (pointer to the new child node) * */ - function putposition($key, $position) { - if (($this->flag & BPT_FLAG_INTERIOR) != BPT_FLAG_INTERIOR) { trigger_error("Can't insert into leaf node", E_USER_ERROR); } - + $validkeys = $this->validkeys; - $last = $this->validkeys+1; - - if ($this->validkeys>=$this->size) { - #trigger_error('No room error', E_USER_WARNING); + $last = $this->validkeys + 1; + + if ($this->validkeys >= $this->size) { + // trigger_error('No room error', E_USER_WARNING); return NOROOMERROR; } - + // store the key - if ($validkeys<0) { // no nodes currently + if ($validkeys < 0) { // no nodes currently d("no keys"); $this->validkeys = 0; - $this->indices[0] = $position; + $this->indices [0] = $position; } else { // there are nodes - $keys =& $this->keys; + $keys = & $this->keys; // is the key there already? if (in_array($key, $keys, true)) { if (array_search($key, $keys, true) < $validkeys) - trigger_error("reinsert of node for existing key ($key)", - E_USER_ERROR); + trigger_error("reinsert of node for existing key ($key)", E_USER_ERROR); } - + $place = BPT_bisect($keys, $key, 0, $validkeys); // insert at position $place array_splice($keys, $place, 0, $key); // delete last element - unset($keys[$last]); - $keys = array_values($keys); # reset array indices - #array_splice($keys, $last, 1); - + unset($keys [$last]); + $keys = array_values($keys); // reset array indices + // array_splice($keys, $last, 1); + // store the index - $indices =& $this->indices; - #echo "inserting $position before ", var_dump($indices,1), "\n"; - array_splice($indices, $place+1, 0, $position); - unset($indices[$last+1]); + $indices = & $this->indices; + // echo "inserting $position before ", var_dump($indices,1), "\n"; + array_splice($indices, $place + 1, 0, $position); + unset($indices [$last + 1]); $indices = array_values($indices); - #array_splice($indices, $last+1, 1); + // array_splice($indices, $last+1, 1); $this->validkeys = $last; } } - /** * deletes from interior nodes * - * @param string $key target key + * @param string $key + * target key */ - function delnode($key) { // {{{ if (($this->flag & BPT_FLAG_INTERIOR) != BPT_FLAG_INTERIOR) { @@ -678,79 +728,79 @@ class BPlusTree_Node { if ($this->validkeys < 0) { trigger_error("No such key (empty)"); } - + $validkeys = $this->validkeys; - $indices =& $this->indices; - $keys =& $this->keys; + $indices = & $this->indices; + $keys = & $this->keys; if (is_null($key)) { $place = 0; $indexplace = 0; } else { $place = array_search($key, $keys, true); - $indexplace = $place+1; + $indexplace = $place + 1; } - #unset($indices[$indexplace]); + // unset($indices[$indexplace]); array_splice($indices, $indexplace, 1); - $indices[] = BPT_NULLSEEK; - #$indices = array_values($indices); - - #unset($keys[$place]); + $indices [] = BPT_NULLSEEK; + // $indices = array_values($indices); + + // unset($keys[$place]); array_splice($keys, $place, 1); - $keys[] = ''; - #$keys = array_values($keys); - + $keys [] = ''; + // $keys = array_values($keys); + $this->validkeys = $validkeys - 1; } - // }}} + // }}} + /** - * slices the $this->keys array to the number of valid keys + * slices the $this->keys array to the number of valid keys * in $this->validkeys * * @returns array array of valid keys */ - function get_keys() { $validkeys = $this->validkeys; - if ($validkeys<=0) { + if ($validkeys <= 0) { return array(); - } + } return array_slice($this->keys, 0, $validkeys); } - - + /** - * mimic's python's map(None, a, b); + * mimic's python's map(None, a, b); * a, b must be of the same size * - * @param array $a first array - * @param array $b second array - * + * @param array $a + * first array + * @param array $b + * second array + * * @returns object {@link pairs} */ function &_pairs($a, $b) { - $x = new pairs($a,$b); + $x = new pairs($a, $b); return $x; - } - /** - * returns an object containing pairs (key, index) + * returns an object containing pairs (key, index) * for all of the valid keys and indices - * - * @param string $leftmost leftmost key corresponding - * to first index (seek) in interior nodes; ignored in leaves * + * @param string $leftmost + * leftmost key corresponding + * to first index (seek) in interior nodes; ignored in leaves + * * @returns object pairs * */ function keys_indices($leftmost) { $keys = $this->get_keys(); if (($this->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { - // interior nodes start with + // interior nodes start with // the pointer to the "less than key[0]" subtree: // we need pairs (key, indices) so we add the leftmost key // on top @@ -760,11 +810,11 @@ class BPlusTree_Node { return $this->_pairs($keys, $indices); } - /** * returns child, searching for $key in an interior node * - * @param string $key target $key + * @param string $key + * target $key * @returns object BPlusTree_Node * */ @@ -774,24 +824,24 @@ class BPlusTree_Node { } if (is_null($key)) $index = 0; - else - $index = array_search($key, $this->keys, true)+1; - - $place = $this->indices[$index]; - if ($place<0) { + else + $index = array_search($key, $this->keys, true) + 1; + + $place = $this->indices [$index]; + if ($place < 0) { debug_print_backtrace(); trigger_error("Invalid position! ($place, $key)", E_USER_ERROR); } - + // fifo - $fifo =& $this->fifo; + $fifo = & $this->fifo; if ($fifo) { - $ff =& $fifo->fifo; - $fd =& $fifo->fifo_dict; - if (isset($fd[$place])) { - $node =& $fd[$place]; - #unset($ff[$place]); + $ff = & $fifo->fifo; + $fd = & $fifo->fifo_dict; + if (isset($fd [$place])) { + $node = & $fd [$place]; + // unset($ff[$place]); $idx = array_search($node, $ff, true); array_splice($ff, $idx, 1); array_unshift($ff, $node); @@ -799,72 +849,73 @@ class BPlusTree_Node { } } - $node =& $this->getclone($place); - $node =& $node->materialize(); + $node = & $this->getclone($place); + $node = & $node->materialize(); return $node; } - /***** leaf mode operations *****/ - + /** + * *** leaf mode operations **** + */ + /** * if leaf returns the next leaf on the right - * */ - function &next() { if (($this->flag & BPT_LEAF_FLAG) != BPT_FLAG_LEAF) { trigger_error("cannot get next for non-leaf", E_USER_ERROR); } - $place = $this->indices[$this->size]; + $place = $this->indices [$this->size]; if ($place == BPT_NULLSEEK) return null; else { - $node =& $this->getclone($place); - $node =& $node->materialize(); + $node = & $this->getclone($place); + $node = & $node->materialize(); return $node; } - } /* - function &prev() { - if (($this->flag & BPT_LEAF_FLAG) != BPT_FLAG_LEAF) { - trigger_error("cannot get next for non-leaf", E_USER_ERROR); - } - $place = $this->prev; - if ($place == BPT_NULLSEEK) - return null; - else { - $node =& $this->getclone($place); - $node =& $node->materialize(); - return $node; - } - - } + * function &prev() { + * if (($this->flag & BPT_LEAF_FLAG) != BPT_FLAG_LEAF) { + * trigger_error("cannot get next for non-leaf", E_USER_ERROR); + * } + * $place = $this->prev; + * if ($place == BPT_NULLSEEK) + * return null; + * else { + * $node =& $this->getclone($place); + * $node =& $node->materialize(); + * return $node; + * } + * + * } */ - + /** * put ($key, $val) in a leaf * - * @param string $key target string - * @param int $val value for $key + * @param string $key + * target string + * @param int $val + * value for $key */ function putvalue($key, $val) { if (!is_string($key)) trigger_error("$key must be string", E_USER_ERROR); - + if (($this->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) { - #print_r($this); + // print_r($this); trigger_error("cannot get next for non-leaf ($key)", E_USER_ERROR); } $validkeys = $this->validkeys; - $indices =& $this->indices; - $keys =& $this->keys; - - if ($validkeys<=0) { // empty - // first entry - $indices[0] = $val; - $keys[0] = $key; + $indices = & $this->indices; + $keys = & $this->keys; + + if ($validkeys <= 0) { // empty + // first entry + $indices [0] = $val; + $keys [0] = $key; $this->validkeys = 1; } else { $place = null; @@ -875,239 +926,243 @@ class BPlusTree_Node { } } if (!is_null($place)) { - $keys[$place] = $key; - $indices[$place] = $val; + $keys [$place] = $key; + $indices [$place] = $val; } else { if ($validkeys >= $this->size) { - #trigger_error("no room", E_USER_WARNING); + // trigger_error("no room", E_USER_WARNING); return NOROOMERROR; } - + $place = BPT_bisect($keys, $key, 0, $validkeys); - $last = $validkeys+1; - - # del keys[validkeys] - # del indices[validkeys] - #array_splice($keys, $validkeys, 1); - unset($keys[$validkeys]); + $last = $validkeys + 1; + + // del keys[validkeys] + // del indices[validkeys] + // array_splice($keys, $validkeys, 1); + unset($keys [$validkeys]); $keys = array_values($keys); - #array_splice($indices, $validkeys, 1); - unset($indices[$validkeys]); + // array_splice($indices, $validkeys, 1); + unset($indices [$validkeys]); $indices = array_values($indices); - + array_splice($keys, $place, 0, $key); array_splice($indices, $place, 0, $val); - #echo implode(', ', $keys), " ::: $place \n"; + // echo implode(', ', $keys), " ::: $place \n"; $this->validkeys = $last; - } } } /** - * for each $key, $index in $keys_indices + * for each $key, $index in $keys_indices * put the correspoding values (assumes this is a leaf) * - * @param object $keys_indices object of type {@link pairs} + * @param object $keys_indices + * object of type {@link pairs} */ function put_all_values($keys_indices) { $this->clear(); - $indices =& $this->indices; - $keys =& $this->keys; - $length = $this->validkeys = $keys_indices->count;#count($keys_indices); + $indices = & $this->indices; + $keys = & $this->keys; + $length = $this->validkeys = $keys_indices->count; // count($keys_indices); if ($length > $this->size) trigger_error("bad length $length", E_USER_ERROR); - - for ($i=0; $i<$length; $i++) { - #list($keys[$i], $indices[$i]) = $keys_indices[$i]; - $keys[$i] = $keys_indices->a[$i]; - $indices[$i] = $keys_indices->b[$i]; + + for($i = 0; $i < $length; $i++) { + // list($keys[$i], $indices[$i]) = $keys_indices[$i]; + $keys [$i] = $keys_indices->a [$i]; + $indices [$i] = $keys_indices->b [$i]; } } - /** - * for each $key, $index in $keys_indices + * for each $key, $index in $keys_indices * put the correspoding seek positions (assumes this is an interior node) * - * @param int $first_position leftmost pointer (to less-than child) - * @param object $keys_indices object of type {@link pairs} - * + * @param int $first_position + * leftmost pointer (to less-than child) + * @param object $keys_indices + * object of type {@link pairs} + * */ - - function put_all_positions($first_position, $keys_positions) { + function put_all_positions($first_position, $keys_positions) { $this->clear(); - $indices =& $this->indices; - $keys =& $this->keys; - $length = $this->validkeys = $keys_positions->count;#count($keys_positions); + $indices = & $this->indices; + $keys = & $this->keys; + $length = $this->validkeys = $keys_positions->count; // count($keys_positions); if ($length > $this->size) { trigger_error("bad length $length", E_USER_ERROR); } - $indices[0] = $first_position; - for ($i=0; $i<$length; $i++) { - #list($keys[$i], $indices[$i+1]) = $keys_positions[$i]; - $keys[$i] = $keys_positions->a[$i]; - $indices[$i+1] = $keys_positions->b[$i]; + $indices [0] = $first_position; + for($i = 0; $i < $length; $i++) { + // list($keys[$i], $indices[$i+1]) = $keys_positions[$i]; + $keys [$i] = $keys_positions->a [$i]; + $indices [$i + 1] = $keys_positions->b [$i]; } - } - + } /** * assuming this is a leaf, returns value for $key - * @param $key string target key + * + * @param $key string + * target key * @returns int|false corresponding integer or false if key is missing * */ - function getvalue(&$key, $loose=false) { - - #d(implode(",",$this->keys)); - #$place = array_search($key, $this->keys); + function getvalue(&$key, $loose = false) { + + // d(implode(",",$this->keys)); + // $place = array_search($key, $this->keys); $place = BPT_bisect($this->keys, $key, 0, $this->validkeys); - if ($this->keys[$place-1] == $key) { - return $this->indices[$place-1]; + if ($this->keys [$place - 1] == $key) { + return $this->indices [$place - 1]; } else { if ($loose) { - if ($place>1) $place--; - $key = $this->keys[$place]; - return $this->indices[$place]; + if ($place > 1) + $place--; + $key = $this->keys [$place]; + return $this->indices [$place]; } trigger_error("key '$key' not found", E_USER_WARNING); return false; } - } /** * if leaf, creates a neighbor for this node: a new leaf * linked to this * - * @param int $position seek position for the new neighborù + * @param int $position + * seek position for the new neighbor� * @returns object BPlusTree_Node * */ function &newneighbour($position) { if (($this->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) trigger_error('cannot make leaf neighbour for non-leaf'); - + // create clone - $neighbour =& $this->getclone($position); + $neighbour = & $this->getclone($position); $size = $this->size; - $indices =& $this->indices; - + $indices = & $this->indices; + // linking siblings - $neighbour->indices[$size] = $indices[$size]; - $indices[$size] = $position; + $neighbour->indices [$size] = $indices [$size]; + $indices [$size] = $position; return $neighbour; } /** * if leaf, returns the leaf next to this + * * @return object BPlusTree_Node */ function &nextneighbour() { - if (($this->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) + if (($this->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) trigger_error('cannot get leaf neighbour for non-leaf'); - + $size = $this->size; - $position = $this->indices[$size]; + $position = $this->indices [$size]; if ($position == BPT_NULLSEEK) { $neighbour = null; } else { $neighbour = $this->getclone($position); $neighbour = $neighbour->materialize(); } - + return $neighbour; - } - + /* - function &prevneighbour() { - if (($this->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) - trigger_error('cannot get leaf neighbour for non-leaf'); - - #$size = $this->size; - $position = $this->prev; # $this->indices[$size]; - if ($position == BPT_NULLSEEK) { - return null; - } else { - $neighbour = $this->getclone($position); - $neighbour = $neighbour->materialize(); - return $neighbour; - } + * function &prevneighbour() { + * if (($this->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) + * trigger_error('cannot get leaf neighbour for non-leaf'); + * + * #$size = $this->size; + * $position = $this->prev; # $this->indices[$size]; + * if ($position == BPT_NULLSEEK) { + * return null; + * } else { + * $neighbour = $this->getclone($position); + * $neighbour = $neighbour->materialize(); + * return $neighbour; + * } + * + * } + */ - }*/ - /** * if leaf, deletes neighbor on the right, and re-link * with the following * - * @param object $next target for deletion - * @param free $free seek position of last free node in free list - * + * @param object $next + * target for deletion + * @param free $free + * seek position of last free node in free list + * * @returns int new free position */ function delnext(&$next, $free) { d("delnext called:"); - #print_r($this); + // print_r($this); $size = $this->size; - if ($this->indices[$size]!=$next->position) { - trigger_error("invalid next pointer ". - "{$this->indices[$size]}!={$next->position})", E_USER_ERROR); + if ($this->indices [$size] != $next->position) { + trigger_error("invalid next pointer " . "{$this->indices[$size]}!={$next->position})", E_USER_ERROR); } - $this->indices[$size] = $next->indices[$size]; + $this->indices [$size] = $next->indices [$size]; return $next->free($free); } /** * if leaf, deletes corresponding value * - * @param string $key target key + * @param string $key + * target key */ - function delvalue($key) { - $keys =& $this->keys; - $indices =& $this->indices; + function delvalue($key) { + $keys = & $this->keys; + $indices = & $this->indices; if (!in_array($key, $keys, true)) { d($keys); - trigger_error ("missing key, can't delete", E_USER_ERROR); + trigger_error("missing key, can't delete", E_USER_ERROR); } $place = array_search($key, $keys, true); $validkeys = $this->validkeys; - $prev = $validkeys-1; - - # delete + $prev = $validkeys - 1; + + // delete array_splice($keys, $place, 1); array_splice($indices, $place, 1); - #unset($keys[$place]); - #$keys[]=''; - #$keys = array_values($keys); - #unset($indices[$place]); - #$indices[] = BPT_NULL; - #$indices = array_values($indices); + // unset($keys[$place]); + // $keys[]=''; + // $keys = array_values($keys); + // unset($indices[$place]); + // $indices[] = BPT_NULL; + // $indices = array_values($indices); - # insert NULLs/empties + // insert NULLs/empties array_splice($keys, $prev, 0, ''); array_splice($indices, $prev, 0, BPT_NULL); - $this->validkeys=$prev;//validkeys-1 - + $this->validkeys = $prev; // validkeys-1 } - + /* - * add self to free list, retunr position as new free position + * add self to free list, retunr position as new free position * * @param int $freenodeposition current last free node * */ function free($freenodeposition) { $this->flag = BPT_FLAG_FREE; - $this->indices[0] = $freenodeposition; + $this->indices [0] = $freenodeposition; $this->store(); return $this->position; } - + /* * assuming self is head of free list, * pop self off freelist, return next free position; @@ -1116,84 +1171,85 @@ class BPlusTree_Node { * @param integer $flag flag for new node * @return object new node * - function unfree($flag) { - $next = $this->indices[0]; - $this->flag = $flag; - $this->validkeys = 0; - $this->indices[0] = BPT_NULLSEEK; - $this->clear(); - return $next; - } + * function unfree($flag) { + * $next = $this->indices[0]; + * $this->flag = $flag; + * $this->validkeys = 0; + * $this->indices[0] = BPT_NULLSEEK; + * $this->clear(); + * return $next; + * } */ - + /** - * get free node of same shape as self from $this->file; + * get free node of same shape as self from $this->file; * make one if none exist; * assume $freeposition is seek position of next free node * - * @param int $freeposition seek position of next freenode - * @param callback $freenode_callback is specified it is a func to call - * with a new free list head, if needed - * + * @param int $freeposition + * seek position of next freenode + * @param callback $freenode_callback + * is specified it is a func to call + * with a new free list head, if needed + * * @returns array(&$node, $newfreeposition) * * - * + * * */ - function getfreenode($freeposition, $freenode_callback=null) { + function getfreenode($freeposition, $freenode_callback = null) { d("GETTING FREE AT $freeposition"); if ($freeposition == BPT_NULLSEEK) { $file = $this->infile; - fseek($file, 0, SEEK_END); + fseek($file, 0, SEEK_END); $position = ftell($file); d("ALLOCATING SPACE..."); - $thenode =& $this->getclone($position); + $thenode = & $this->getclone($position); $thenode->store(); - return array(&$thenode, BPT_NULLSEEK); + return array( + &$thenode, + BPT_NULLSEEK + ); } else { $position = $freeposition; $thenode = $this->getclone($position); // get old node $thenode = $thenode->materialize(); // ptr to next - $next = $thenode->indices[0]; + $next = $thenode->indices [0]; if (!is_null($freenode_callback)) { call_user_func($freenode_callback, $next); } - - $thenode->BplusTree_Node( - $this->flag, - $this->size, - $this->keylen, - $position, - $this->infile - ); - + + $thenode->BplusTree_Node($this->flag, $this->size, $this->keylen, $position, $this->infile); + $thenode->store(); // save reinit'ed node - return array(&$thenode, $next); + return array( + &$thenode, + $next + ); } } - /** * * write this to file * - * @param bool $force forces write back if fifo is enabled, defaults to false - * + * @param bool $force + * forces write back if fifo is enabled, defaults to false + * */ - function store($force = false) { - // {{{ + // {{{ $position = $this->position; if (is_null($position)) - trigger_error("position cannot be null",E_USER_ERROR); + trigger_error("position cannot be null", E_USER_ERROR); - $fifo =& $this->fifo; + $fifo = & $this->fifo; if (!$force && $fifo) { - $fd =& $fifo->fifo_dict; - if (isset($fd[$this->position]) && $fd[$position] === $this) { + $fd = & $fifo->fifo_dict; + if (isset($fd [$this->position]) && $fd [$position] === $this) { $this->dirty = true; return; // defer processing } @@ -1211,9 +1267,9 @@ class BPlusTree_Node { } return $last; - } - //}}} + + // }}} /** * load node from file @@ -1225,122 +1281,119 @@ class BPlusTree_Node { $position = $this->position; if ($this->fifo) { - $fifo =& $this->fifo; - $dict =& $fifo->fifo_dict; - $ff =& $fifo->fifo; - if (isset($dict[$position])) { - $node =& $dict[$position]; - if ($node !== $ff[0]) { + $fifo = & $this->fifo; + $dict = & $fifo->fifo_dict; + $ff = & $fifo->fifo; + if (isset($dict [$position])) { + $node = & $dict [$position]; + if ($node !== $ff [0]) { $nidx = array_search($node, $ff, true); - unset($ff[$nidx]); + unset($ff [$nidx]); array_unshift($ff, $node); } return $node; } } - $f = $this->infile; + $f = $this->infile; fseek($f, $position); $data = fread($f, $this->storage); $this->delinearize($data); - if ($this->fifo) { $this->add_to_fifo(); } - - return $this; } /** + * * @returns string binary string encoding this node */ function linearize() { $params = array( - 'C2L'.($this->size+1), + 'C2L' . ($this->size + 1), $this->flag, $this->validkeys ); - - foreach($this->indices as $i) - $params[] = $i; - - $s = call_user_func_array('pack', $params); - - + + foreach ($this->indices as $i) + $params [] = $i; + + $s = call_user_func_array('pack', $params); + $x = ''; - for($i = 0; $i<$this->validkeys; $i++) { - $k = $this->keys[$i]; - if (strlen($k)>$this->keylen) + for($i = 0; $i < $this->validkeys; $i++) { + $k = $this->keys [$i]; + if (strlen($k) > $this->keylen) trigger_error("Invalid keylen for '$k'", E_USER_ERROR); $x .= str_pad($k, $this->keylen, chr(0)); } - $x = str_pad($x, $this->size*$this->keylen, chr(0)); - - + $x = str_pad($x, $this->size * $this->keylen, chr(0)); + $s .= $x; $l = strlen($s); if (strlen($s) != $this->storage) { trigger_error("bad storage $l != {$this->storage}", E_USER_ERROR); } - + return $s; } /** * get properties of this node from the string $s encoded via {@link BPlusTree_Node::linearize} * - * @param string $s binary string - * + * @param string $s + * binary string + * */ - - function delinearize($s) { - //{{{ - if (strlen($s)!=$this->storage) + function delinearize($s) { + // {{{ + if (strlen($s) != $this->storage) trigger_error("bad storage", E_USER_ERROR); - - + $x = 'Cflag/Cvalidkeys/'; - $n = $this->size+1; - for ($i = 0; $i<$n; $i++) { + $n = $this->size + 1; + for($i = 0; $i < $n; $i++) { $x .= "lindices{$i}/"; } $arr = unpack($x, $s); - - $this->flag = $arr['flag']; - $this->validkeys = $arr['validkeys']; - - for ($i = 0; $i<$n; $i++) { - $this->indices[$i] = $arr["indices{$i}"]; + + $this->flag = $arr ['flag']; + $this->validkeys = $arr ['validkeys']; + + for($i = 0; $i < $n; $i++) { + $this->indices [$i] = $arr ["indices{$i}"]; } - for ($i = 0, $j = ($n*4+2); $i<$this->validkeys; $i++, $j+=$this->keylen) { + for($i = 0, $j = ($n * 4 + 2); $i < $this->validkeys; $i++, $j += $this->keylen) { - $this->keys[$i] = rtrim(substr($s, $j, $this->keylen)); + $this->keys [$i] = rtrim(substr($s, $j, $this->keylen)); } - } - //}}} + // }}} + // foo dump /** * * prints a dump of the tree on scree - * @param string $indent custom indentation * + * @param string $indent + * custom indentation + * */ - function dump($indent='') { - //{{{ + function dump($indent = '') { + // {{{ $flag = $this->flag; if ($flag == BPT_FLAG_FREE) { echo "free->", $this->position, "\n"; - $nextp = $this->indices[0]; - if ($nextp!=BPT_NULLSEEK) { - $next =& $this->getclone($nextp); - $next =& $next->materialize(); + $nextp = $this->indices [0]; + if ($nextp != BPT_NULLSEEK) { + $next = & $this->getclone($nextp); + $next = & $next->materialize(); $next->dump(); } else { echo "!last\n"; @@ -1350,74 +1403,90 @@ class BPlusTree_Node { $nextindent = $indent . " "; echo $indent; switch ($flag) { - case BPT_FLAG_ROOT: echo "root"; break; - case BPT_FLAG_INTERIOR: echo "interior"; break; - case BPT_FLAG_LEAF: echo "leaf"; break; - case BPT_FLAG_LEAFANDROOT: echo "root&leaf"; break; - default : echo "invalid flag??? ", $flag; + case BPT_FLAG_ROOT: + echo "root"; + break; + case BPT_FLAG_INTERIOR: + echo "interior"; + break; + case BPT_FLAG_LEAF: + echo "leaf"; + break; + case BPT_FLAG_LEAFANDROOT: + echo "root&leaf"; + break; + default: + echo "invalid flag??? ", $flag; } - - echo "($flag) "; + + echo "($flag) "; echo " ", $this->position, " valid=", $this->validkeys, "\n"; echo $indent, "keys {", implode(', ', $this->keys), "}\n"; - echo $indent, "seeks {", implode(", ", $this->indices),"}\n"; + echo $indent, "seeks {", implode(", ", $this->indices), "}\n"; if (($flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { reset($this->indices); - while($i = array_shift($this->indices)) { - if ($i!=BPT_NULLSEEK) { + while ($i = array_shift($this->indices)) { + if ($i != BPT_NULLSEEK) { // interior - $n =& $this->getclone($i); - $n =& $n->materialize(); + $n = & $this->getclone($i); + $n = & $n->materialize(); $n->dump($nextindent); } else { - //leaf + // leaf continue; } } } echo $indent, "*****\n"; + } - }//}}}*/ - + // }}}*/ /** * adds this node to fifo */ function add_to_fifo() { - $fifo =& $this->fifo; - $ff =& $fifo->fifo; - $dict =& $fifo->fifo_dict; - + $fifo = & $this->fifo; + $ff = & $fifo->fifo; + $dict = & $fifo->fifo_dict; + $position = $this->position; - if(isset($dict[$position])) { - $old =& $dict[$position]; - unset($dict[$position]); - # ff.remove(old) + if (isset($dict [$position])) { + $old = & $dict [$position]; + unset($dict [$position]); + // ff.remove(old) array_splice($ff, array_search($old, $ff, true), 1); } - $dict[$this->position] =& $this; - array_splice($ff, 0, 0, array(&$this)); - if (count($ff)>$this->fifo->fifosize) { - $lastidx = count($ff)-1; - $last = $ff[$lastidx]; - unset($ff[$lastidx]); - unset($dict[$last->position]); + $dict [$this->position] = & $this; + array_splice($ff, 0, 0, array( + &$this + )); + if (count($ff) > $this->fifo->fifosize) { + $lastidx = count($ff) - 1; + $last = $ff [$lastidx]; + unset($ff [$lastidx]); + unset($dict [$last->position]); if ($last->dirty) { $last->store(true); } } - $is_o=true; - while((list(,$v)=each($ff)) && $is_o=is_object($v)); - if (!$is_o) {trigger_error('ERR', E_USER_ERROR);} + $is_o = true; + // Arvid: The loop doesn't do anything - but contains a deprecated each(). Commented out. + // while ((list (, $v) = each($ff)) && $is_o = is_object($v)) + // ; + if (!$is_o) { + trigger_error('ERR', E_USER_ERROR); + } } /** - * @param int $size defaults to 33 * + * @param int $size + * defaults to 33 + * */ - function enable_fifo($size = 33) { - if ($size<5 || $size>1000000) { + if ($size < 5 || $size > 1000000) { trigger_error("size not valid $size"); } $this->fifo = new BPlusTree_Node_Fifo($size); @@ -1425,9 +1494,7 @@ class BPlusTree_Node { /** * disables fifo (first flushes to disk) - * */ - function disable_fifo() { if ($this->fifo) { $this->fifo->flush_fifo(); @@ -1435,7 +1502,6 @@ class BPlusTree_Node { } } - } /** @@ -1445,98 +1511,113 @@ class BPlusTree_Node { * public methods are only {@link BPlusTree::getitem} * {@link BPlusTree::setitem} {@link BPlusTree::delitem} * {@link BPlusTree::walker} - * - * */ +class BPlusTree { -class BPlusTree { /** + * * @var int number of values */ var $length = null; + /** + * * @var bool used for deferred writes (if fifo is enabled */ var $dirty = false; - # var $headerformat = "%10d %10d %10d %10d %10d\n"; + + // var $headerformat = "%10d %10d %10d %10d %10d\n"; /** + * * @var int seek position of root in file */ var $root_seek = BPT_NULLSEEK; + /** - * @var int seek position of the start of the freelist * + * @var int seek position of the start of the freelist + * */ var $free = BPT_NULLSEEK; + /** + * * @var object BPlusTree_Node root node */ - var $root = null; /* */ + var $root = null; + + /* */ /** + * * @var int length of the file header in bytes */ var $headersize; + /** + * * @var bool true if fifo is enabled */ var $fifo_enabled = false; /** * constructor - * @param resource $infile resource of open file - * @param int $position offset from the beginning of the file (usually 0) - * @param int $nodesize size of the node - * @param int $keylen maximum lenght of a key in bytes (unicode extended chars evaluate to two chars) + * + * @param resource $infile + * resource of open file + * @param int $position + * offset from the beginning of the file (usually 0) + * @param int $nodesize + * size of the node + * @param int $keylen + * maximum lenght of a key in bytes (unicode extended chars evaluate to two chars) */ - - function __construct($infile, $pos=null, $nodesize=null, $keylen=10) { - if (!is_null($keylen) && $keylen<=2) { + function __construct($infile, $pos = null, $nodesize = null, $keylen = 10) { + if (!is_null($keylen) && $keylen <= 2) { trigger_error("$keylen must be greater than 2", E_USER_ERROR); } $this->root_seek = BPT_NULLSEEK; $this->free = BPT_NULLSEEK; $this->root = null; $this->file = $infile; - #if ($nodesize<6) trigger_error("nodesize must be >= 6", E_USER_ERROR); + // if ($nodesize<6) trigger_error("nodesize must be >= 6", E_USER_ERROR); $this->nodesize = $nodesize; $this->keylen = $keylen; if (is_null($pos)) { $pos = 0; } $this->position = $pos; - $this->headersize = 4*4+6; /* 4 4-byte longs, 1 char, 5-byte magic string*/ + $this->headersize = 4 * 4 + 6; /* 4 4-byte longs, 1 char, 5-byte magic string */ } /** * returns an iterator for the tree - * @param string $keylower key lower limit of the iterator - * @param bool|int $includelower if true $keylower is included in the iterator; - * if $includelower > 1 then 'loose' search is assumed: - * the tree will be walked starting from - * the key $k in the tree such as $k <= $keylower - * and such as there are NO other keys $k' - * such as $k < $k' <= $keylower - * @param string $keyupper key upper bound of the iterator - * @param bool $includeupper if true $keyupper is included in the iterator + * + * @param string $keylower + * key lower limit of the iterator + * @param bool|int $includelower + * if true $keylower is included in the iterator; + * if $includelower > 1 then 'loose' search is assumed: + * the tree will be walked starting from + * the key $k in the tree such as $k <= $keylower + * and such as there are NO other keys $k' + * such as $k < $k' <= $keylower + * @param string $keyupper + * key upper bound of the iterator + * @param bool $includeupper + * if true $keyupper is included in the iterator */ - function &walker( - &$keylower, - $includelower =null, - $keyupper =null, - $includeupper =null - ) { - - $o = new BPlusWalker($this, $keylower, $includelower, $keyupper, $includeupper); - return $o; - + function &walker(&$keylower, $includelower = null, $keyupper = null, $includeupper = null) { + $o = new BPlusWalker($this, $keylower, $includelower, $keyupper, $includeupper); + return $o; } - + /** + * * @returns array array of properties of this object */ - function init_params() { + function init_params() { return array( - $this->file, + $this->file, $this->position, $this->nodesize, $this->keylen @@ -1544,18 +1625,21 @@ class BPlusTree { } /** + * * @returns object BPlusTree_Node of the root */ function get_root() { return $this->root; - } + } /** * updates the head of the freelist and writes back to file - * @param int $position seek position of the head of the freelist - */ + * + * @param int $position + * seek position of the head of the freelist + */ function update_freelist($pos) { - if ($this->free!=$pos) { + if ($this->free != $pos) { $this->free = $pos; $this->reset_header(); } @@ -1567,52 +1651,42 @@ class BPlusTree { */ function startup() { if (is_null($this->nodesize) || is_null($this->keylen)) { - trigger_error("cannot initialize without nodesize, keylen specified\n") ; + trigger_error("cannot initialize without nodesize, keylen specified\n"); } $this->length = 0; - $this->root_seek = 22; //pack('a5LCL3',...) + $this->root_seek = 22; // pack('a5LCL3',...) $this->reset_header(); $file = $this->file; fseek($file, 0, SEEK_END); - $this->root = new BplusTree_Node( - BPT_FLAG_LEAFANDROOT, - $this->nodesize, $this->keylen, $this->root_seek, $file - ); + $this->root = new BplusTree_Node(BPT_FLAG_LEAFANDROOT, $this->nodesize, $this->keylen, $this->root_seek, $file); $this->root->store(); } - /** + /** * reload the bplustree from file and setup for use */ - function open() { $file = $this->file; - if ($this->get_parameters()===false) + if ($this->get_parameters() === false) return false; - $this->root = new BplusTree_Node( - BPT_FLAG_LEAFANDROOT, - $this->nodesize, - $this->keylen, - $this->root_seek, - $file - ); - $this->root =& $this->root->materialize(); + $this->root = new BplusTree_Node(BPT_FLAG_LEAFANDROOT, $this->nodesize, $this->keylen, $this->root_seek, $file); + $this->root = & $this->root->materialize(); return true; } /** * enable fifo - * @param int $size defaults to 33 + * + * @param int $size + * defaults to 33 */ - - function enable_fifo($size=33) { + function enable_fifo($size = 33) { $this->fifo_enabled = true; $this->root->enable_fifo($size); } /** * disables fifo (writes back header to file if needed) - * */ function disable_fifo() { $this->fifo_enabled = false; @@ -1627,11 +1701,8 @@ class BPlusTree { * * @returns string header string */ - function _makeheader() { - return pack('a5LCL3', BPT_VERSION_MAGIC, - $this->length, $this->keylen, - $this->nodesize, $this->root_seek, $this->free); + return pack('a5LCL3', BPT_VERSION_MAGIC, $this->length, $this->keylen, $this->nodesize, $this->root_seek, $this->free); } /** @@ -1639,20 +1710,19 @@ class BPlusTree { * fifo is again disabled */ function reset_header() { - if ($this->fifo_enabled) { $this->dirty = true; d("[FIFO]: deferring header reset"); return; } - $file = $this->file; + $file = $this->file; fseek($file, $this->position); - + $s = $this->_makeheader(); - + fwrite($file, $s); } - + /** * reads back properties/parameters of this tree from file; * raises an error if version magic is wrong @@ -1660,246 +1730,250 @@ class BPlusTree { * @returns bool false on failure, true on success */ function get_parameters() { - $file = $this->file; + $file = $this->file; fseek($file, $this->position); $data = fread($file, $this->headersize); $hdr = unpack('a5magic/Llength/Ckeylen/Lnodesize/Lroot_seek/Lfree', $data); - if ($hdr['magic']!=BPT_VERSION_MAGIC) { - trigger_error("Version magic mismatch ({$hdr['magic']}!=" - .BPT_VERSION_MAGIC.')', E_USER_WARNING); + if ($hdr ['magic'] != BPT_VERSION_MAGIC) { + trigger_error("Version magic mismatch ({$hdr['magic']}!=" . BPT_VERSION_MAGIC . ')', E_USER_WARNING); return false; } - $this->length = $hdr['length']; - $this->keylen = $hdr['keylen']; - $this->nodesize = $hdr['nodesize']; - $this->root_seek = $hdr['root_seek']; - $this->free = $hdr['free']; + $this->length = $hdr ['length']; + $this->keylen = $hdr ['keylen']; + $this->nodesize = $hdr ['nodesize']; + $this->root_seek = $hdr ['root_seek']; + $this->free = $hdr ['free']; return true; } /** + * * @returns length of the tree (number of values) */ - function length() { + function length() { if (is_null($this->length)) { - if (false===$this->get_parameters()) return false; + if (false === $this->get_parameters()) + return false; } return $this->length; } /** - * @param string &$key key to find. - * @param bool $loose if true searches the tree for the "nearest" key to $key; - * + * + * @param + * string &$key key to find. + * @param bool $loose + * if true searches the tree for the "nearest" key to $key; + * * @returns int associated value - * + * */ - function getitem(&$key, $loose=false) { + function getitem(&$key, $loose = false) { if (is_null($this->root)) trigger_error("not open!", E_USER_ERROR); return $this->find($key, $this->root, $loose); } - + /** * traverses tree starting from $node, searching for $key - * @param string $key target key - * @param object BPlusTree_Node starting node * + * @param string $key + * target key + * @param + * object BPlusTree_Node starting node + * * @returns int|bool value at the leaf node containing key or false if key is missing * */ - function find(&$key, &$node, $loose=false) { - + function find(&$key, &$node, $loose = false) { while (($node->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { - + $thesekeys = $node->keys; $validkeys = $node->validkeys; - - #d(array_slice($thesekeys, 0, $validkeys)); + + // d(array_slice($thesekeys, 0, $validkeys)); $place = BPT_bisect($thesekeys, $key, 0, $validkeys); - if ($place>=$validkeys || BPT_keycmp($thesekeys[$place],$key)>0) { - #$thesekeys[$place]>$key) { + if ($place >= $validkeys || BPT_keycmp($thesekeys [$place], $key) > 0) { + // $thesekeys[$place]>$key) { if ($place == 0) $nodekey = null; else - $nodekey=$thesekeys[$place-1]; + $nodekey = $thesekeys [$place - 1]; } else { $nodekey = $key; } - - - $node =& $node->getnode($nodekey); + + $node = & $node->getnode($nodekey); } - + return $node->getvalue($key, $loose); } /** - * @param $key target key + * + * @param $key target + * key * @returns bool false if key does not exists, true otherwise */ - function has_key(&$key, $loose=false) { - if (@$this->getitem($key, $loose)!==false) { + function has_key(&$key, $loose = false) { + if (@$this->getitem($key, $loose) !== false) { return true; } else { return false; } } - /** * sets an item in the tree with key $key and value $val * * @param string $key - * @param integer $val (internally stored as a 4byte long: keep it in mind!) - * - * + * @param integer $val + * (internally stored as a 4byte long: keep it in mind!) + * + * */ - function setitem($key, $val) { if (!is_numeric($val)) trigger_error("Second parameter must be numeric", E_USER_ERROR); $curr_length = $this->length; - $root =& $this->root; - if (is_null($root)) trigger_error("not open", E_USER_ERROR); - if (!is_string($key)) trigger_error("$key must be string", E_USER_ERROR); - if (strlen($key)>$this->keylen) + $root = & $this->root; + if (is_null($root)) + trigger_error("not open", E_USER_ERROR); + if (!is_string($key)) + trigger_error("$key must be string", E_USER_ERROR); + if (strlen($key) > $this->keylen) trigger_error("$key is too long: MAX is {$this->keylen}", E_USER_ERROR); + d("STARTING FROM ROOT..."); - d( "STARTING FROM ROOT..." ); - $test1 = $this->set($key, $val, $this->root); if (!is_null($test1)) { d("SPLITTING ROOT"); - - // getting new rightmost interior node - list($leftmost, $node) = $test1; - #print_r($test1); - d("LEFTMOST [$leftmost]"); - - // getting new non-leaf root - list($newroot, $this->free) = $root->getfreenode($this->free); - $newroot->flag = BPT_FLAG_ROOT; - - /* - if ($root->flag == BPT_FLAG_LEAFANDROOT) { - $root->flag = BPT_FLAG_LEAF; - } else { - $root->flag = BPT_FLAG_INTERIOR; - }*/ - // zero-ing root flag (makes an interior or leaf node + // getting new rightmost interior node + list ($leftmost, $node) = $test1; + // print_r($test1); + d("LEFTMOST [$leftmost]"); + + // getting new non-leaf root + list ($newroot, $this->free) = $root->getfreenode($this->free); + $newroot->flag = BPT_FLAG_ROOT; + + /* + * if ($root->flag == BPT_FLAG_LEAFANDROOT) { + * $root->flag = BPT_FLAG_LEAF; + * } else { + * $root->flag = BPT_FLAG_INTERIOR; + * } + */ + + // zero-ing root flag (makes an interior or leaf node // respectively from a normal root or a leaf-root) $root->flag &= ~BPT_FLAG_ROOT_BIT; - + $newroot->clear(); $newroot->putfirstindex($root->position); $newroot->putnode($leftmost, $node); - $this->root =& $newroot; + $this->root = & $newroot; $this->root_seek = $newroot->position; $newroot->store(); $root->store(); $this->reset_header(); - d("root split."); + d("root split."); } else { - if ($this->length!=$curr_length) { + if ($this->length != $curr_length) { // length changed: updating header $this->reset_header(); } } } - /** * traverses subtree starting at $node, searching a place for $key * and associates $val; split nodes if needed * - * This function is not meant to be called outside the class, it is a + * This function is not meant to be called outside the class, it is a * support method for {@link BPlusTree::setitem} * * @param string $key - * @param int $val value associated to $key - * @param object BPlusTree_Node starting node - * - * @returns array|null a pair (leftmost, newnode) where "leftmost" is + * @param int $val + * value associated to $key + * @param + * object BPlusTree_Node starting node + * + * @returns array|null a pair (leftmost, newnode) where "leftmost" is * the leftmost key in newnode, and newnode is the split node; * returns null if no split took place */ - - function set($key, $val, &$node) { - //{{{ - $keys =& $node->keys; + function set($key, $val, &$node) { + // {{{ + $keys = & $node->keys; $validkeys = $node->validkeys; - if (($node->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { + if (($node->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { d("NON LEAF: FIND DESCENDANT"); // non-leaf: find descendant to insert - d($keys); + d($keys); $place = BPT_bisect($keys, $key, 0, $validkeys); - if ($place >= $validkeys || BPT_keycmp($keys[$place],$key)>=0) { - #$keys[$place]>=$key) { + if ($place >= $validkeys || BPT_keycmp($keys [$place], $key) >= 0) { + // $keys[$place]>=$key) { // insert at previous node $index = $place; - } else { - $index = $place +1 ; + } else { + $index = $place + 1; } - + if ($index == 0) $nodekey = null; - else - $nodekey =$keys[$place-1]; - - $nextnode =$node->getnode($nodekey); + else + $nodekey = $keys [$place - 1]; + + $nextnode = $node->getnode($nodekey); $test = $this->set($key, $val, $nextnode); // split ? if (!is_null($test)) { - list($leftmost, $insertnode) = $test; + list ($leftmost, $insertnode) = $test; // TRY $TRY = $node->putnode($leftmost, $insertnode); if ($TRY == NOROOMERROR) { - - d( "$key::SPLIT!" ); + + d("$key::SPLIT!"); // EXCEPT - + $insertindex = $insertnode->position; - - list($newnode, $this->free) = - $node->getfreenode( - $this->free, - array(&$this, 'update_freelist') - ); + + list ($newnode, $this->free) = $node->getfreenode($this->free, array( + &$this, + 'update_freelist' + )); $newnode->flag = BPT_FLAG_INTERIOR; - + $ki = $node->keys_indices("dummy"); - - #list($dummy, $firstindex) = $ki[0]; #each($ki); - $firstindex = $ki->b[0]; - - #$ki = array_slice($ki, 1); + + // list($dummy, $firstindex) = $ki[0]; #each($ki); + $firstindex = $ki->b [0]; + + // $ki = array_slice($ki, 1); $ki->remove(0); - #print_r($ki); + // print_r($ki); // insert new pair - #BPT_insort($ki, array($leftmost, $insertindex)); + // BPT_insort($ki, array($leftmost, $insertindex)); $ki->insort($leftmost, $insertindex); - - $newleftmost = $this->divide_entries( - $firstindex, - $node, - $newnode, - $ki - ); - + + $newleftmost = $this->divide_entries($firstindex, $node, $newnode, $ki); + $node->store(); $newnode->store(); - return array($newleftmost, &$newnode); - - } else { - - d( "$key::NO SPLIT" ); + return array( + $newleftmost, + &$newnode + ); + } else { + + d("$key::NO SPLIT"); d($node->keys); $node->store(); return null; // no split @@ -1909,47 +1983,49 @@ class BPlusTree { // leaf d("FOUND LEAF:"); d($keys); - if (!in_array($key, $keys, true) - || array_search($key, $keys, true) >= $validkeys) { - $newlength = $this->length +1; + if (!in_array($key, $keys, true) || array_search($key, $keys, true) >= $validkeys) { + $newlength = $this->length + 1; } else { $newlength = $this->length; } - + d("[LEAF] TRYING TO PUT $key=>$val"); - if ($node->putvalue($key, $val)==NOROOMERROR) { + if ($node->putvalue($key, $val) == NOROOMERROR) { d("GOT NOROOMERROR"); $ki = $node->keys_indices("dummy"); - #BPT_insort($ki, array($key, $val)); + // BPT_insort($ki, array($key, $val)); $ki->insort($key, $val); - list($newnode, $this->free) = - $node->getfreenode( - $this->free, - array(&$this, 'update_freelist') - ); + list ($newnode, $this->free) = $node->getfreenode($this->free, array( + &$this, + 'update_freelist' + )); d("CREATE NEW NEIGHBOUR"); - $newnode =& $node->newneighbour($newnode->position); + $newnode = & $node->newneighbour($newnode->position); $newnode->flag = BPT_FLAG_LEAF; $newleftmost = $this->divide_entries(0, $node, $newnode, $ki); $node->store(); - #print_r($node); - #print_r($newnode); + // print_r($node); + // print_r($newnode); $newnode->store(); $this->length = $newlength; - return array($newleftmost, &$newnode); + return array( + $newleftmost, + &$newnode + ); } else { - d("STORING NODE [{$node->position}]") ; + d("STORING NODE [{$node->position}]"); d($node->keys); - + $node->store(); $this->length = $newlength; return null; } } } - //}}} + // }}} + /** * * removes key from tree at node $node; @@ -1958,29 +2034,31 @@ class BPlusTree { * not meant to be called outside the class, it is a support method * for {@link BPlusTree::delitem} * - * @param $key target key - * @param $node node from which start - * + * @param $key target + * key + * @param $node node + * from which start + * * @returns array a pair(&$leftmost, $size): if leftmost changes it is a string with the new leftmost * of $node otherwise returns array(null, $size)- caller will restructure node, if needed * size is the new size of $node * */ - function remove($key, &$node, $NESTING=0) { + function remove($key, &$node, $NESTING = 0) { $newnodekey = null; d("NESTING LEVEL $NESTING"); d("($NESTING) current size = {$this->nodesize}"); - - // first of all we check if it is non-leaf + + // first of all we check if it is non-leaf if (($node->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { // non-leaf - $keys =& $node->keys; - $validkeys =$node->validkeys; + $keys = & $node->keys; + $validkeys = $node->validkeys; $place = BPT_bisect($keys, $key, 0, $validkeys); - - if ($place>=$validkeys || BPT_keycmp($keys[$place],$key)>=0) { - #$keys[$place]>=$key) { + + if ($place >= $validkeys || BPT_keycmp($keys [$place], $key) >= 0) { + // $keys[$place]>=$key) { // delete occurs before $place // (remember that indices are [i_0,i_1,...,i_n] // where i_0 points to the node where all keys are < K_search @@ -1990,62 +2068,58 @@ class BPlusTree { // delete occurs in $place (k_i <= K_search < k_(i+1) ) $index = $place + 1; } - - if ($index==0) { + + if ($index == 0) { $nodekey = null; } else { - $nodekey = $keys[$place-1]; + $nodekey = $keys [$place - 1]; } - + // get child node - $nextnode =& $node->getnode($nodekey); - + $nextnode = & $node->getnode($nodekey); + // RECURSION! remove from nextnode; - // returns new leftmost if changed, otherwise null, + // returns new leftmost if changed, otherwise null, // and new size of the child node - list($lm, $size) = $this->remove($key, $nextnode, $NESTING+1); - + list ($lm, $size) = $this->remove($key, $nextnode, $NESTING + 1); + // check now for size of nodesize: is it too small? // (less than half) $nodesize = $this->nodesize; - $half = (int)($nodesize/2); - - # if($size==0) trigger_error("SIZE==0", E_USER_WARNING); - + $half = (int) ($nodesize / 2); + + // if($size==0) trigger_error("SIZE==0", E_USER_WARNING); + if ($size < $half) { d("($NESTING) node too small ($size<$nodesize/2), redistribute children"); - + // node is too small, need to redistribute // children - + if (is_null($nodekey) && $validkeys == 0) { - #print_r($node); - trigger_error( - "invalid node, only one child", - E_USER_ERROR - ); + // print_r($node); + trigger_error("invalid node, only one child", E_USER_ERROR); } - if ($place >= $validkeys) { // final node in row, get previous - $rightnode =& $nextnode; - $rightkey = $nodekey; - if ($validkeys<=1) { + $rightnode = & $nextnode; + $rightkey = $nodekey; + if ($validkeys <= 1) { $leftkey = null; } else { - $leftkey = $keys[$place-2]; + $leftkey = $keys [$place - 2]; } - $leftnode =& $node->getnode($leftkey); + $leftnode = & $node->getnode($leftkey); } else { // non-final, get next - $leftnode =& $nextnode; + $leftnode = & $nextnode; $leftkey = $nodekey; - + if ($index == 0) { - $rightkey = $keys[0]; + $rightkey = $keys [0]; } else { - $rightkey = $keys[$place]; + $rightkey = $keys [$place]; } $rightnode = $node->getnode($rightkey); } @@ -2053,45 +2127,36 @@ class BPlusTree { $rightki = $rightnode->keys_indices($rightkey); $leftki = $leftnode->keys_indices($leftkey); - #$ki = array_merge($leftki, $rightki); + // $ki = array_merge($leftki, $rightki); $leftki->append($rightki); - $ki =& $leftki; + $ki = & $leftki; - #array_splice ($leftki, count($leftki), 0, $rightki); - - $lki = $ki->count;#count($ki); - + // array_splice ($leftki, count($leftki), 0, $rightki); + + $lki = $ki->count; // count($ki); + // merging? - if (($lki>$nodesize) || ( - ($leftnode->flag & BPT_FLAG_LEAF)!=BPT_FLAG_LEAF - && - ($lki>=$nodesize) - )) { + if (($lki > $nodesize) || (($leftnode->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF && ($lki >= $nodesize))) { // redistribute - #list($newleftkey, $firstindex) = $ki[0]; - $newleftkey = $ki->a[0]; - $firstindex = $ki->b[0]; + // list($newleftkey, $firstindex) = $ki[0]; + $newleftkey = $ki->a [0]; + $firstindex = $ki->b [0]; if (is_null($leftkey)) { $newleftkey = $lm; } - if (($leftnode->flag&BPT_FLAG_LEAF)!=BPT_FLAG_LEAF) { + if (($leftnode->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) { // kill first pair - #$ki = array_slice($ki, 1); + // $ki = array_slice($ki, 1); $ki->remove(0); } - $newrightkey = $this->divide_entries( - $firstindex, - $leftnode, - $rightnode, - $ki - ); - + $newrightkey = $this->divide_entries($firstindex, $leftnode, $rightnode, $ki); + // delete, reinsert right $node->delnode($rightkey); $node->putnode($newrightkey, $rightnode); - + // same for left if first changed - if (!is_null($leftkey) && $leftkey!=$newleftkey) { + if (!is_null($leftkey) && $leftkey != $newleftkey) { $node->delnode($leftkey); $node->putnode($newleftkey, $leftnode); } @@ -2104,28 +2169,23 @@ class BPlusTree { d($leftnode->keys); d($leftnode->indices); d($rightnode->indices); - #list($newleftkey, $firstindex) = $ki[0]; - $newleftkey = $ki->a[0]; - $firstindex = $ki->b[0]; + // list($newleftkey, $firstindex) = $ki[0]; + $newleftkey = $ki->a [0]; + $firstindex = $ki->b [0]; - if (($leftnode->flag&BPT_FLAG_LEAF)!=BPT_FLAG_LEAF) { - $leftnode->put_all_positions( - $firstindex, - $ki->slice(1) - #array_slice($ki, 1) - ); + if (($leftnode->flag & BPT_FLAG_LEAF) != BPT_FLAG_LEAF) { + $leftnode->put_all_positions($firstindex, $ki->slice(1)); + // array_slice($ki, 1) } else { $leftnode->put_all_values($ki); } - - if ($rightnode->flag==BPT_FLAG_LEAF) { - $this->free = $leftnode->delnext( - $rightnode, $this->free - ); + + if ($rightnode->flag == BPT_FLAG_LEAF) { + $this->free = $leftnode->delnext($rightnode, $this->free); } else { $this->free = $rightnode->free($this->free); } - if (!is_null($leftkey) && $newleftkey!=$leftkey) { + if (!is_null($leftkey) && $newleftkey != $leftkey) { d("$newleftkey!=$leftkey"); $node->delnode($leftkey); $node->putnode($newleftkey, $leftnode); @@ -2133,10 +2193,10 @@ class BPlusTree { $node->delnode($rightkey); $node->store(); $leftnode->store(); - d('redist:'); + d('redist:'); d($node->keys); d($leftnode->keys); - + $this->reset_header(); } if (is_null($leftkey)) @@ -2149,7 +2209,7 @@ class BPlusTree { // we return a new leftmost key to update parent // ($lm is null if no update is needed) $newnodekey = $lm; - } elseif(!is_null($lm)) { + } elseif (!is_null($lm)) { // child's leftmost has changed: // delete old reference $node->delnode($nodekey); @@ -2157,134 +2217,133 @@ class BPlusTree { $node->putnode($lm, $nextnode); } } // end restructuring if - } else { - //leaf, base case: just delete. - if ($node->validkeys<1) { + // leaf, base case: just delete. + if ($node->validkeys < 1) { // only for empty root trigger_error("No such key $key", E_USER_ERROR); } - $first=$node->keys[0]; + $first = $node->keys [0]; d($node->keys); $node->delvalue($key); d($node->keys); - $rest = $node->keys[0]; - if ($first!=$rest) { + $rest = $node->keys [0]; + if ($first != $rest) { $newnodekey = $rest; } $node->store(); $this->length--; - + d("NEWNODEKEY: $newnodekey"); d("VALIDKEYS: {$node->validkeys}"); } d($node->keys); - return array($newnodekey, $node->validkeys); + return array( + $newnodekey, + $node->validkeys + ); } - /** * - * equally divides $entries ("array" of pairs (key,index) - + * equally divides $entries ("array" of pairs (key,index) - * implemented with a pair object) between two nodes $node1 and $node2 * - * @param int $firstindex if interior node, leftmost index (pointer to less-than sub-tree) for $node1 - * @param object $node1 BPlusTree_Node first destination node - * @param object $node2 BplusTree_Node second destination node - * @param object $entries {@link pairs} object - * + * @param int $firstindex + * if interior node, leftmost index (pointer to less-than sub-tree) for $node1 + * @param object $node1 + * BPlusTree_Node first destination node + * @param object $node2 + * BplusTree_Node second destination node + * @param object $entries + * {@link pairs} object + * * @returns string leftmost key of $node1 */ - function divide_entries($firstindex, &$node1, &$node2, &$entries) { -//{{{ - #$middle = (int)(count($entries)/2); - $middle = ceil($entries->count/2); + // {{{ + // $middle = (int)(count($entries)/2); + $middle = ceil($entries->count / 2); d("divide entries at $middle"); - - #$left = array_slice($entries, 0, $middle); - #$right = array_slice($entries, $middle); + + // $left = array_slice($entries, 0, $middle); + // $right = array_slice($entries, $middle); $left = $entries->slice(0, $middle); $right = $entries->slice($middle); - - - if (($node1->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { - d("DIVIDING INTERIOR\n"); - #list($leftmost, $midindex) = $right[0]; - $leftmost = $right->a[0]; - $midindex = $right->b[0]; - + + if (($node1->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { + d("DIVIDING INTERIOR\n"); + // list($leftmost, $midindex) = $right[0]; + $leftmost = $right->a [0]; + $midindex = $right->b [0]; + $node1->put_all_positions($firstindex, $left); - #$node2->put_all_positions($midindex, array_slice($right, 1)); + // $node2->put_all_positions($midindex, array_slice($right, 1)); $node2->put_all_positions($midindex, $right->slice(1)); d($node1->keys); d($node2->keys); - if (in_array( - array_fill(0,$node1->size,''), - array($node1->keys,$node2->keys), true) - ) { + if (in_array(array_fill(0, $node1->size, ''), array( + $node1->keys, + $node2->keys + ), true)) { trigger_error("splitting an empty node!", E_USER_ERROR); } - return $leftmost; + return $leftmost; } else { - d("DIVIDING non-INTERIOR"); + d("DIVIDING non-INTERIOR"); $node1->put_all_values($left); $node2->put_all_values($right); d($node1->keys); d($node2->keys); // returns right leftmost - #return $right[0][0]; - return $right->a[0]; + // return $right[0][0]; + return $right->a [0]; } } -// }}} - + // }}} + /** * delete item $key - * @param string $key the key to delete * + * @param string $key + * the key to delete + * */ - function delitem($key) { $root = $this->root; $currentlength = $this->length; - - $this->remove($key, $root, $NESTING=0); - + + $this->remove($key, $root, $NESTING = 0); + if ($root->flag == BPT_FLAG_ROOT) { $validkeys = $root->validkeys; - - if ($validkeys <1) { + + if ($validkeys < 1) { - - if ($validkeys<0) { - trigger_error( - "invalid empty non-leaf root", - E_USER_ERROR - ); + if ($validkeys < 0) { + trigger_error("invalid empty non-leaf root", E_USER_ERROR); } - - - $this->root =& $root->getnode(null); - $newroot =& $this->root; + + $this->root = & $root->getnode(null); + $newroot = & $this->root; $this->root_seek = $newroot->position; $this->free = $root->free($this->free); $this->reset_header(); /* - if ($newroot->flag == BPT_FLAG_LEAF) { - $newroot->flag = BPT_FLAG_LEAFANDROOT; - } else { - $newroot->flag = BPT_FLAG_ROOT; - } - */ + * if ($newroot->flag == BPT_FLAG_LEAF) { + * $newroot->flag = BPT_FLAG_LEAFANDROOT; + * } else { + * $newroot->flag = BPT_FLAG_ROOT; + * } + */ $newroot->flag |= BPT_FLAG_ROOT_BIT; $newroot->store(); } elseif ($this->length != $currentlength) { $this->reset_header(); } - } elseif($root->flag != BPT_FLAG_LEAFANDROOT) { + } elseif ($root->flag != BPT_FLAG_LEAFANDROOT) { trigger_error("invalid flag for root", E_USER_ERROR); } elseif ($this->length != $currentlength) { $this->reset_header(); @@ -2292,58 +2351,51 @@ class BPlusTree { } function _dump() { - $free =& $this->root->getclone($this->free); - for ($i=$this->headersize; - !feof($this->file); - fseek($this->file, $i), $i+=$free->storage) { - $s = fread($this->file, $free->storage); - $free->delinearize($s); - #print_r($free); - } + $free = & $this->root->getclone($this->free); + for($i = $this->headersize; !feof($this->file); fseek($this->file, $i), $i += $free->storage) { + $s = fread($this->file, $free->storage); + $free->delinearize($s); + // print_r($free); + } } /** * dumps contents of the tree to screen */ - function dump() { - $this->root->dump() ; + $this->root->dump(); if ($this->free != BPT_NULLSEEK) { - $free =& $this->root->getclone($this->free); - $free =& $free->materialize(); + $free = & $this->root->getclone($this->free); + $free = & $free->materialize(); $free->dump(); } } - - + } class BPlusWalker { - + var $tree; + var $keylower; + var $includelower; + var $keyupper; + var $includeupper; - - function __construct( - &$tree, - &$keylower, - $includelower=null, - $keyupper=null, - $includeupper=null){ - - $this->tree =& $tree; + function __construct(&$tree, &$keylower, $includelower = null, $keyupper = null, $includeupper = null) { + $this->tree = & $tree; $this->keylower = $keylower; $this->includelower = $includelower; $this->keyupper = $keyupper; $this->includeupper = $includeupper; - if ($this->tree->get_root()==null) { + if ($this->tree->get_root() == null) { $this->tree->open(); } $node = $this->tree->get_root(); - while(BPT_FLAG_INTERIOR == ($node->flag & BPT_FLAG_INTERIOR)) { + while (BPT_FLAG_INTERIOR == ($node->flag & BPT_FLAG_INTERIOR)) { if (is_null($keylower)) { $nkey = null; @@ -2351,20 +2403,20 @@ class BPlusWalker { $keys = $node->get_keys(); $n_keys = count($keys); $place = BPT_bisect($keys, $keylower); - if ($place==0) { + if ($place == 0) { $nkey = null; - } elseif ($place>$n_keys) { - $nkey = $keys[$n_keys-1]; + } elseif ($place > $n_keys) { + $nkey = $keys [$n_keys - 1]; } else { - $nkey = $keys[$place-1]; + $nkey = $keys [$place - 1]; } } - - $node =& $node->getnode($nkey); + + $node = & $node->getnode($nkey); } - - $this->startnode =& $node; - $this->node =& $node; + + $this->startnode = & $node; + $this->node = & $node; $this->node_index = null; $this->valid = 0; @@ -2373,51 +2425,50 @@ class BPlusWalker { } function first() { - $this->node =& $this->startnode; - $node =& $this->node; - - $keys =& $node->keys; + $this->node = & $this->startnode; + $node = & $this->node; + + $keys = & $node->keys; $keylower = $this->keylower; $keyupper = $this->keyupper; - $validkeys= $node->validkeys; - $this->valid=0; - if ($keylower==null) { + $validkeys = $node->validkeys; + $this->valid = 0; + if ($keylower == null) { $this->node_index = 0; - $this->valid=1; + $this->valid = 1; } elseif (in_array($keylower, $keys, true) && $this->includelower) { $this->node_index = array_search($keylower, $keys, true); $index = $this->node_index; - if ($index<$validkeys) { + if ($index < $validkeys) { $this->valid = 1; } } if (!$this->valid) { $place = BPT_bisect($keys, $keylower, 0, $validkeys); - if ($place < $validkeys || ($place==$validkeys && $this->includelower>1)) { + if ($place < $validkeys || ($place == $validkeys && $this->includelower > 1)) { if ($place > 0) $index = $place - 1; - else $index = $place; - + else + $index = $place; + $this->node_index = $index; - $testk = $keys[$index]; + $testk = $keys [$index]; /* - if ($testk>$keylower || - ($this->includelower && $testk==$keylower)) { - $this->valid = true; - } else { - $this->valid = false; - } - */ - $this->valid = BPT_keycmp($testk,$keylower)<0||#$testk>$keylower || - ($this->includelower && ($this->includelower>1 || $testk==$keylower) ); - - + * if ($testk>$keylower || + * ($this->includelower && $testk==$keylower)) { + * $this->valid = true; + * } else { + * $this->valid = false; + * } + */ + $this->valid = BPT_keycmp($testk, $keylower) < 0 || // $testk>$keylower || + ($this->includelower && ($this->includelower > 1 || $testk == $keylower)); + $this->keylower = $testk; - } else { - $next =& $node->nextneighbour(); + $next = & $node->nextneighbour(); if (!is_null($next)) { - $this->startnode =& $next; + $this->startnode = & $next; $this->first(); return; } else { @@ -2426,75 +2477,77 @@ class BPlusWalker { } if ($this->valid && !is_null($keyupper)) { $key = $this->current_key(); - $this->valid= ( - BPT_keycmp($key,$keyupper)<0 #$key<$keyupper - ||($this->includeupper && $key==$keyupper)); + $this->valid = (BPT_keycmp($key, $keyupper) < 0 || // $key<$keyupper + ($this->includeupper && $key == $keyupper)); } } } function current_key() { - if ($this->valid) return $this->node->keys[$this->node_index]; - else trigger_error("WALKER: Not a valid index ({$this->node_index})"); + if ($this->valid) + return $this->node->keys [$this->node_index]; + else + trigger_error("WALKER: Not a valid index ({$this->node_index})"); } function current_value() { - if ($this->valid) return $this->node->indices[$this->node_index]; - else trigger_error("WALKER: Not a valid index ({$this->node_index})"); + if ($this->valid) + return $this->node->indices [$this->node_index]; + else + trigger_error("WALKER: Not a valid index ({$this->node_index})"); } function current() { if ($this->valid) { return array( - $this->node->keys[$this->node_index], - $this->node->indices[$this->node_index] + $this->node->keys [$this->node_index], + $this->node->indices [$this->node_index] ); } else { - trigger_error("WALKER: Not a valid index ({$this->node_index})"); + trigger_error("WALKER: Not a valid index ({$this->node_index})"); } } function next() { - $nextp = $this->node_index+1; - $node =& $this->node; - if ($nextp>=$node->validkeys) { - $next =& $node->nextneighbour(); + $nextp = $this->node_index + 1; + $node = & $this->node; + if ($nextp >= $node->validkeys) { + $next = & $node->nextneighbour(); if (is_null($next)) { $this->valid = 0; return; } - $this->node =& $next; - $node =& $next; + $this->node = & $next; + $node = & $next; $nextp = 0; } - if($node->validkeys <= $nextp) { + if ($node->validkeys <= $nextp) { $this->valid = 0; } else { - $testkey = $node->keys[$nextp]; + $testkey = $node->keys [$nextp]; $keyupper = $this->keyupper; - $this->valid =( is_null($keyupper) || - BPT_keycmp($testkey,$keyupper)<0|| - #$testkey < $keyupper || - ($this->includeupper && $testkey == $keyupper) ); - if ($this->valid) $this->node_index = $nextp; + $this->valid = (is_null($keyupper) || BPT_keycmp($testkey, $keyupper) < 0 || + // $testkey < $keyupper || + ($this->includeupper && $testkey == $keyupper)); + if ($this->valid) + $this->node_index = $nextp; } - + return $this->valid; - } - + } class caching_BPT extends BPlusTree { var $cache = array(); - function getitem(&$key, $loose=false) { - if (isset($this->cache[$key])) - return $this->cache[$key]; - else { - $this->cache[$key] = parent::getitem($key, $loose); - return $this->cache[$key]; + function getitem(&$key, $loose = false) { + if (isset($this->cache [$key])) + return $this->cache [$key]; + else { + $this->cache [$key] = parent::getitem($key, $loose); + return $this->cache [$key]; } } @@ -2506,20 +2559,24 @@ class caching_BPT extends BPlusTree { trigger_error("operation not permitted in caching_BPT", E_USER_WARNING); } - function setitem($key, $val) { $this->nope(); } + function setitem($key, $val) { + $this->nope(); + } - function delitem($key) { $this->nope(); } + function delitem($key) { + $this->nope(); + } } class SBPlusTree extends BPlusTree { - - var $maxstring; var $stringfile; - - function __construct($infile, $stringfile, - $maxstring = 256, - $pos=null, $nodesize=null, $keylen=null) { - parent::__construct($infile, $pos, $nodesize, $keylen); + + var $maxstring; + + var $stringfile; + + function __construct($infile, $stringfile, $maxstring = 256, $pos = null, $nodesize = null, $keylen = null) { + parent::__construct($infile, $pos, $nodesize, $keylen); $this->stringfile = $stringfile; $this->maxstring = $maxstring; } @@ -2544,24 +2601,26 @@ class SBPlusTree extends BPlusTree { fseek($this->stringfile, $seek); } // nul-pad string - if (strlen($s>$this->maxstring)) + if (strlen($s > $this->maxstring)) $x = substr($s, 0, $this->maxstring); $x = str_pad($s, $this->maxstring, chr(0)); fwrite($this->stringfile, $x); return $seek; } - function getitem(&$key, $loose=false) { + function getitem(&$key, $loose = false) { $seek = $this->has_key($key, $loose); - return is_numeric($seek)? $this->getstring($seek) : false; + return is_numeric($seek) ? $this->getstring($seek) : false; } /** - * @param $key target key + * + * @param $key target + * key * @returns int seek point if key exists, 0 otherwise */ - function has_key(&$key, $loose=false) { - return @parent::getitem($key, $loose); + function has_key(&$key, $loose = false) { + return @parent::getitem($key, $loose); } function setitem($key, $val) { @@ -2570,15 +2629,11 @@ class SBPlusTree extends BPlusTree { return $seek; } - function &walker( - &$keylower, - $includelower =null, - $keyupper =null, - $includeupper =null - ) { - $o = new SBPlusWalker($this, $keylower, $includelower, $keyupper, $includeupper); - return $o; - } + function &walker(&$keylower, $includelower = null, $keyupper = null, $includeupper = null) { + $o = new SBPlusWalker($this, $keylower, $includelower, $keyupper, $includeupper); + return $o; + } + } class SBPlusWalker extends BPlusWalker { @@ -2587,28 +2642,23 @@ class SBPlusWalker extends BPlusWalker { $id = parent::current_value(); return $this->tree->getstring($id); } - + } class caching_SBPT extends SBPlusTree { var $cache = array(); - function __construct($infile, $stringfile, - $maxstring = 256, - $pos=null, $nodesize=null, $keylen=null) { - - parent::__construct($infile, $stringfile, - $maxstring, - $pos, $nodesize, $keylen); + function __construct($infile, $stringfile, $maxstring = 256, $pos = null, $nodesize = null, $keylen = null) { + parent::__construct($infile, $stringfile, $maxstring, $pos, $nodesize, $keylen); } - function getitem(&$key, $loose=false) { - if (isset($this->cache[$key])) - return $this->cache[$key]; + function getitem(&$key, $loose = false) { + if (isset($this->cache [$key])) + return $this->cache [$key]; else { $item = parent::getitem($key, $loose); - $this->cache[$key] = $item; + $this->cache [$key] = $item; return $item; } } @@ -2621,28 +2671,32 @@ class caching_SBPT extends SBPlusTree { trigger_error("operation not permitted in caching_BPT", E_USER_WARNING); } - function setitem($key, $val) { $this->nope(); } + function setitem($key, $val) { + $this->nope(); + } - function delitem($key) { $this->nope(); } + function delitem($key) { + $this->nope(); + } } class BPlusUtils { - function recopy_bplus($fromfile, $tofile, $class='BPlusTree') { + function recopy_bplus($fromfile, $tofile, $class = 'BPlusTree') { $fromtree = new $class($fromfile); $fromtree->open; - list($f, $p, $n, $k) = $fromtree->init_params(); - $totree = new $class($tofile, $p, $n, $k); + list ($f, $p, $n, $k) = $fromtree->init_params(); + $totree = new $class($tofile, $p, $n, $k); $totree->startup(); - return BPlusUtils::recopy_tree($fromtree,$totree); + return BPlusUtils::recopy_tree($fromtree, $totree); } function recopy_tree($fromtree, $totree) { - list($f, $p, $n, $k) = $totree->init_params(); - // .... + list ($f, $p, $n, $k) = $totree->init_params(); + // .... } - + } diff --git a/fp-includes/core/core.draft.php b/fp-includes/core/core.draft.php index 4f0bb75..b6dbe63 100644 --- a/fp-includes/core/core.draft.php +++ b/fp-includes/core/core.draft.php @@ -1,223 +1,204 @@ _cachefile = CACHE_DIR . 'draft_index.php'; - return parent::__construct(); - } - - - function _checkFile($directory, $file) { - - $f = "$directory/$file"; - if ( is_dir($f) && ctype_digit($file)) { - return 1; - } - - if (fnmatch('entry*'.EXT, $file)) { - $id=basename($file,EXT); - $arr=draft_parse($id); - - //$this->add($id, $arr['subject']); - $this->_list[$id] = $arr['subject']; - - return 0; - } - - } - - } - - function &draft_init() { - global $draftdb; - if (!isset($draftdb)) - $draftdb = new draft_indexer; - return $draftdb; - } - - - function draft_getlist() { - - static $list = array(); - - if (!$list) { - $obj =& draft_init(); - $list = $obj->getList(); - krsort($list); - } - - return $list; - - } - - function draft_parse($id) { - - if ($fname=draft_exists($id)) { - - $entry = io_load_file($fname); - - $entry = utils_kexplode($entry); - if (!isset($entry['categories'])) - $entry['categories'] = array(); - else - $entry['categories'] = explode(',', $entry['categories']); - - return $entry; - } - return array(); +class draft_indexer extends fs_filelister { + + var $_varname = 'cache'; + + var $_cachefile = null; + + var $_directory = DRAFT_DIR; + + function __construct() { + $this->_cachefile = CACHE_DIR . 'draft_index.php'; + return parent::__construct(); } - - function draft_save(&$entry, $id=null, $update_index = false, $update_date=false) { - - if (!$id) { - $id = bdb_idfromtime('entry', $entry['date']); + function _checkFile($directory, $file) { + $f = "$directory/$file"; + if (is_dir($f) && ctype_digit($file)) { + return 1; } - - $ed = entry_dir($id); - $dd = draft_dir($id); - if (file_exists($ed.EXT)) { - - // move collateral files - @rename($ed, $dd); + if (fnmatch('entry*' . EXT, $file)) { + $id = basename($file, EXT); + $arr = draft_parse($id); - if ($update_index) { - // delete normal entry - fs_delete($ed.EXT); + // $this->add($id, $arr['subject']); + $this->_list [$id] = $arr ['subject']; - // remove from normal flow - $o =& entry_init(); - $o->delete($id, null); - } - + return 0; } - - $new_entry = entry_prepare($entry); - if ($new_entry['categories']) - $new_entry['categories']=implode(',', $entry['categories']); - else unset($new_entry['categories']); - - $string = utils_kimplode($new_entry); - + } - if (!io_write_file($dd.EXT, $string)) { - return false; - } else return $id; +} + +function &draft_init() { + global $draftdb; + if (!isset($draftdb)) + $draftdb = new draft_indexer(); + return $draftdb; +} + +function draft_getlist() { + static $list = array(); + + if (!$list) { + $obj = & draft_init(); + $list = $obj->getList(); + krsort($list); + } + + return $list; +} + +function draft_parse($id) { + if ($fname = draft_exists($id)) { + $entry = io_load_file($fname); + + $entry = utils_kexplode($entry); + if (!isset($entry ['categories'])) + $entry ['categories'] = array(); + else + $entry ['categories'] = explode(',', $entry ['categories']); + + return $entry; + } + return array(); +} + +function draft_save(&$entry, $id = null, $update_index = false, $update_date = false) { + if (!$id) { + $id = bdb_idfromtime('entry', $entry ['date']); + } + + $ed = entry_dir($id); + $dd = draft_dir($id); + + if (file_exists($ed . EXT)) { + + // move collateral files + @rename($ed, $dd); + + if ($update_index) { + // delete normal entry + fs_delete($ed . EXT); + + // remove from normal flow + $o = & entry_init(); + $o->delete($id, null); + } + } + + $new_entry = entry_prepare($entry); + if ($new_entry ['categories']) + $new_entry ['categories'] = implode(',', $entry ['categories']); + else + unset($new_entry ['categories']); + + $string = utils_kimplode($new_entry); + + if (!io_write_file($dd . EXT, $string)) { return false; - - } + } else + return $id; - function draft_dir($id) { - if (!preg_match('|^entry[0-9]{6}-[0-9]{6}$|', $id)) - return false; - //$date = date_from_id($id); - //$f = CONTENT_DIR . "{$date['y']}/{$date['m']}/$id"; - return DRAFT_DIR . $id; - //return $f; - - - } - - function draft_exists($id) { - - $dir = draft_dir($id); - if (!$dir) - return false; - - $f = $dir .EXT; - if (file_exists($f)) - return $f; - + return false; +} + +function draft_dir($id) { + if (!preg_match('|^entry[0-9]{6}-[0-9]{6}$|', $id)) return false; - } + // $date = date_from_id($id); + // $f = CONTENT_DIR . "{$date['y']}/{$date['m']}/$id"; + return DRAFT_DIR . $id; + // return $f; +} - function draft_delete($id) { - $dir = draft_dir($id); - - $f=$dir.EXT; - if (!file_exists($f)) - return false; - - //$draftdb =& draft_init(); - //$draftdb->delete($id); - fs_delete_recursive($dir); - - return fs_delete($f); - } +function draft_exists($id) { + $dir = draft_dir($id); + if (!$dir) + return false; - /* - function draft_from_entry($entryid) { - $dir = entry_dir($entryid); - //$dir2 = str_replace('entry', 'draft', $dir); - $dir2 = draft_dir($entryid); - @rename($dir, $dir2); - @rename($dir.EXT, $dir2.EXT); - } - */ + $f = $dir . EXT; + if (file_exists($f)) + return $f; - function draft_to_entry($draftid) { - - $dir = draft_dir($draftid); - $dir2 = entry_dir($draftid); - - @rename($dir, $dir2); - draft_delete($draftid); - } - - - function smarty_block_draftlist($params, $content, &$smarty, &$repeat) { - global $fpdb; - - if ($list = draft_getlist()) { - $smarty->assign('draft_list', $list); - return $content; - } - - } - - - function smarty_block_draft($params, $content, &$smarty, &$repeat) { - - static $list = array(); - - $smarty->assign(array( 'subject'=>'', - 'content'=>'', - 'date'=>'', - 'author'=>'', - 'version'=>'', - 'id'=>'' - ) - ); - $arr =& $smarty->get_template_vars('draft_list'); - - $id = $subject = null; - if ($arr) - list($id, $subject)=each($arr); - - if ($id){ - $smarty->assign('subject', $subject); - $smarty->assign('id', $id); - } - - $repeat = (bool) $id; + return false; +} - return $content; +function draft_delete($id) { + $dir = draft_dir($id); + + $f = $dir . EXT; + if (!file_exists($f)) + return false; + + // $draftdb =& draft_init(); + // $draftdb->delete($id); + fs_delete_recursive($dir); + + return fs_delete($f); +} + +/* + * function draft_from_entry($entryid) { + * $dir = entry_dir($entryid); + * //$dir2 = str_replace('entry', 'draft', $dir); + * $dir2 = draft_dir($entryid); + * @rename($dir, $dir2); + * @rename($dir.EXT, $dir2.EXT); + * } + */ +function draft_to_entry($draftid) { + $dir = draft_dir($draftid); + $dir2 = entry_dir($draftid); + + @rename($dir, $dir2); + draft_delete($draftid); +} + +function smarty_block_draftlist($params, $content, &$smarty, &$repeat) { + global $fpdb; + + if ($list = draft_getlist()) { + $smarty->assign('draft_list', $list); + return $content; + } +} + +function smarty_block_draft($params, $content, &$smarty, &$repeat) { + static $list = array(); + + $smarty->assign(array( + 'subject' => '', + 'content' => '', + 'date' => '', + 'author' => '', + 'version' => '', + 'id' => '' + )); + $arr = & $smarty->get_template_vars('draft_list'); + + $id = $subject = null; + if ($arr) { + $firstElement = utils_array_kshift($arr); + $id = array_keys($firstElement) [0]; + $subject = $firstElement [$id]; } + if ($id) { + $smarty->assign('subject', $subject); + $smarty->assign('id', $id); + } + $repeat = (bool) $id; - $smarty->register_block('draft_block', 'smarty_block_draftlist'); - $smarty->register_block('draft', 'smarty_block_draft'); + return $content; +} +$smarty->register_block('draft_block', 'smarty_block_draftlist'); +$smarty->register_block('draft', 'smarty_block_draft'); ?> diff --git a/fp-includes/core/core.entry.php b/fp-includes/core/core.entry.php index 691a733..64777cf 100755 --- a/fp-includes/core/core.entry.php +++ b/fp-includes/core/core.entry.php @@ -1,872 +1,818 @@ position, - $this->nodesize, - $this->keylen - ); - - $this->open(); - } - - } - - class entry_index { - - var $indices = array(); - var $_offset = 0; - var $_chunksize = 30; - var $_keysize = 12; - - var $_lock_file = null; - - - function __construct() { - $this->_lock_file = CACHE_DIR.'bpt.lock'; - - $this->catlist = entry_categories_list(); - - // only main index s a SBPlus (string BPlus): - // the other (other categories) are managed - // as if they were simple BPlus trees, so - // values in key,value pairs won't - // be strings but integers - // - // the integer will be the seek position - // in the SBPlus' string file - // - // they'll be loaded back with the string file - // as SBPlus trees: the string-key, string-value pair - // will be returned - - if ($oldfile = file_exists($f=INDEX_DIR.'index-0.dat')) - $mode = 'r+b'; - else - $mode = 'w+b'; - - $this->indices[0] = new SBPlusTree( - fopen($f, $mode), - fopen(INDEX_DIR.'index.strings.dat', $mode), - 256, - $this->_offset, - $this->_chunksize, - $this->_keysize - ); - - if ($oldfile) - $this->indices[0]->open(); - else - $this->indices[0]->startup(); - - - } - - function _lock_acquire($exclusive=true, $cat=0) { - if (file_exists($this->_lock_file)) { - trigger_error("Could not acquire write lock on INDEX. ". - "Didn't I told you FlatPress is not designed for concurrency, already? ;) ". - "Don't worry: your entry has been saved as draft!", E_USER_WARNING); - return false; - } - - // simulates atomic write by writing to a file, then moving in place - $tmp = $this->_lock_file.".tmp"; - if (io_write_file($tmp, 'dummy')) { - if (rename($tmp, $this->_lock_file)) { - return true; - } - } - - return false; - - } - - function _lock_release($cat=0) { - if (file_exists($this->_lock_file)) { - return @unlink($this->_lock_file); - } else { - trigger_error("Lock file did not exist: ignoring (index was already unlocked.)", E_USER_NOTICE); - return 2; - } - - } - - function &get_index($cat=0) { - if (!is_numeric($cat)) - trigger_error("CAT must be an integer ($cat was given)", E_USER_ERROR); - if (!isset($this->indices[$cat])) { - $f = INDEX_DIR.'index-'.$cat.'.dat'; - if ($oldfile = file_exists($f)) - $mode = 'r+b'; - else $mode = 'w+b'; - - $this->indices[$cat] = new BPlusTree( - fopen($f, $mode), - $this->_offset, - $this->_chunksize, - $this->_keysize - ); - if ($oldfile) - $this->indices[$cat]->open(); - else $this->indices[$cat]->startup(); - } - return $this->indices[$cat]; - } - - function add($id, $entry, $del = array(), $update_title = true) { - $key = entry_idtokey($id); - $val = $entry['subject']; - - if (!$this->_lock_acquire()) return false; // we're DOOMED! - - $main =& $this->get_index(); - $seek = null; - - // title must not be updated, let's get the offset value from has_key - if (!$update_title) - $seek = $main->has_key($key, $val); - - // if seek is null, then there is no such key, and we must set it - // in the main index - if (!is_numeric($seek)) - $seek = $main->setitem($key, $val); - - // key has been set, let's set the other indices (if any), and link them - // to the title string using $seek - - if (isset($entry['categories']) && is_array($entry['categories'])) { - - $categories = array(); - - foreach ($entry['categories'] as $cat) { - - // skip non-numeric special categories (such as 'draft') - if (!is_numeric($cat)) continue; - - $categories[] = $cat; - - // traverse the full cat tree (in linearized form) - // to update categories which eventually aren't - // explicitly listed - while ($parent = $this->catlist[ $cat ]) { - $categories[] = $parent; - $cat = $parent; - } - } - - // delete any duplicate - $categories = array_unique($categories); - - foreach ($categories as $cat) { - $this_index =& $this->get_index($cat); - $this_index->setitem($key, $seek); - } - } - - // if the set of indices changed, some might have to be deleted - if ($del) { - foreach($del as $cat) { - // echo 'DEL '. $cat,"\n"; - if (!is_numeric($cat)) continue; - $this_index =& $this->get_index($cat); - $this_index->delitem($key); - } - } - - return $this->_lock_release(); - - } - - function delete($id, $entry) { - $key = entry_idtokey($id); - - if (!$this->_lock_acquire()) return false; // we're DOOMED! - - $main =& $this->get_index(); - $main->delitem($key); - - - if (isset($entry['categories']) && is_array($entry['categories'])) { - foreach ($entry['categories'] as $cat) { - if (!is_numeric($cat)) continue; - $this_index =& $this->get_index($cat); - if ($this_index->has_key($key)) - $this_index->delitem($key); - } - } - - return $this->_lock_release(); - - } - - } - - class entry_archives extends fs_filelister { - - var $_directory = CONTENT_DIR; - var $_y = null; - var $_m = null; - var $_d = null; - - var $_count = 0; - - var $_filter = 'entry*'; - - function __construct($y, $m = null, $d = null) { - - $this->_y = $y; - $this->_m = $m; - $this->_d = $d; - - $this->_directory .= "$y/"; - - if ($m){ - - $this->_directory .= "$m/"; - - if ($d) { - $this->_filter = "entry$y$m$d*"; - } - - } - - return parent::__construct(); - } - - function _checkFile($directory, $file) { - $f = "$directory/$file"; - if ( is_dir($f) && ctype_digit($file)) { - return 1; - } - - if (fnmatch($this->_filter.EXT, $file)) { - $id=basename($file,EXT); - $this->_count++; - array_push($this->_list, $id); - return 0; - } - } - - function getList() { - rsort($this->_list); - return parent::getList(); - } - - function getCount() { - return $this->_count; - } - - } - - /* //work in progress - class entry { - - var $_indexer; - var $id; - - function entry($id, $content) { - //$this->_indexer =& $indexer; - } - - function get($field) { - $field = strtolower($field); - if (!isset($this->$field)) { - // if it is not set - // tries to fetch from the database - $arr = entry_parse($id); - while(list($field, $val) = each($arr)) - $this->$field = $val; - - // if still is not set raises an error - if (!isset($this->$field)) - trigger_error("$field is not set", E_USER_NOTICE); - return; - - - } - - return $this->$field; - - } - - function set($field, $val) { - $field = strtolower($field); - $this->$field = $val; - } - - } - */ - /** - * function entry_init - * fills the global array containing the entry object - */ - function &entry_init() { - - #global $fpdb; - #$fpdb->init(); - - static $entry_index = null; - - if (is_null($entry_index)) - $entry_index= new entry_index; - - return $entry_index; - - } - - function &entry_cached_index($id_cat) { - - $F = INDEX_DIR.'index-'.$id_cat.'.dat'; + * opens the index belonging to a given category + * + * @params int $id_cat + */ + function __construct($id_cat = 0) { + $F = INDEX_DIR . 'index-' . $id_cat . '.dat'; if (!file_exists($F)) { - $o = false; - } else { - $o = new entry_cached_index($id_cat); + trigger_error("Can't find index '{$F}'", E_USER_ERROR); } - - return $o; - + + parent::__construct(fopen($F, 'rb'), fopen(INDEX_DIR . 'index.strings.dat', 'rb'), 256, $this->position, $this->nodesize, $this->keylen); + + $this->open(); } - - - /* - function entry_query($params=array()){ - - global $fpdb; - $queryid = $fpdb->query($params); - $fpdb->doquery($queryid); - - - } - - function entry_hasmore() { - global $fpdb; - return $fpdb->hasmore(); - - } - - function entry_get() { - $fpdb->get(); - } - */ - - function entry_keytoid($key) { - $date = substr($key,0,6); - $time = substr($key,6); - return "entry{$date}-{$time}"; - } - - function entry_idtokey($id) { - return substr($id, 5, 6) . substr($id, 12); - } - - function entry_timetokey($time) { - return date('ymdHis', $time); - } - - function entry_keytotime($key) { - $arr[ 'y' ] = substr($key, 0, 2); - $arr[ 'm' ] = substr($key, 2, 2); - $arr[ 'd' ] = substr($key, 4, 2); - - $arr[ 'H' ] = substr($key, 6, 2); - $arr[ 'M' ] = substr($key, 8, 2); - $arr[ 'S' ] = substr($key, 10, 2); - - return mktime($arr['H'], $arr['M'], $arr['S'], - $arr['m'], $arr['d'], $arr['y']); - } - - function entry_idtotime($id) { - $date = date_from_id($id); - return $date['time']; - } - - function entry_list() { - - trigger_error('function deprecated', E_USER_ERROR); - - $obj =& entry_init(); - - $entry_arr = $obj->getList(); - - - if ($entry_arr) { - krsort($entry_arr); - return $entry_arr; - } - } - - function entry_exists($id) { - $f = entry_dir($id).EXT; - return file_exists($f)? $f : false; - } - - function entry_dir($id, $month_only = false) { - if (!preg_match('|^entry[0-9]{6}-[0-9]{6}$|', $id)) - return false; - $date = date_from_id($id); - if ($month_only) - $f = CONTENT_DIR . "{$date['y']}/{$date['m']}/"; - else - $f = CONTENT_DIR . "{$date['y']}/{$date['m']}/$id"; - return $f; - - - } - - function entry_parse($id, $raw=false) { - - $f = entry_exists($id); - if (!$f) - return array(); - - $fc = io_load_file($f); - - if (!$fc) - return array(); - - $arr = utils_kexplode($fc); - - // propagates the error if entry does not exist - - - if (isset($arr['categories']) && // fix to bad old behaviour: - (trim($arr['categories']) != '')) { - - - $cats = (array)explode(',',$arr['categories']); - $arr['categories'] = (array) $cats; - - - - } else $arr['categories'] = array(); - - // if (!is_array($arr['categories'])) die(); - - if (!isset($arr['AUTHOR'])) { - global $fp_config; - $arr['AUTHOR'] = $fp_config['general']['author']; - } - - if ($raw) return $arr; - return $arr; - - } - - - /** - * function entry_get_comments - * - * @param string id entry id - * @param array entry entry content array by ref; 'commentcount' field is added to the array - * - * @return object comment_indexer as reference - * - */ - - function &entry_get_comments($id, &$count) { - $obj = new comment_indexer($id); - - $count = count($obj->getList()); - - return $obj; - - } - - - function entry_categories_encode($cat_file) { - - - //if ($string = io_load_file(CONTENT_DIR . 'categories.txt')) { - $lines = explode("\n", trim($cat_file)); - $idstack = $result = $indentstack=array(); - - while (!empty($lines)) { - - $v = array_pop($lines); - - $vt = trim($v); - - if ($vt) { - - $text=''; - $indent = utils_countdashes($vt, $text); - - $val = explode(':', $text); - - $id = trim($val[1]); - $label = trim($val[0]); - - // IDs must be strictly positive - - if ($label && $id <= 0) return -1; - - - - if (empty($indentstack)) { - array_push($indentstack,$indent); - array_push($idstack, $id); - $indent_old = $indent; - } else { - $indent_old = end($indentstack); - } - - if ($indent < $indent_old) { - array_push($indentstack, $indent); - array_push($idstack, $id); - } elseif ($indent > $indent_old) { - $idstack = array($id); - $indentstack = array($indent); - } else { - array_pop($idstack); - $idstack = array($id); - } - - - - $result['rels'][$id] = $idstack; - $result['defs'][$id] = $label; - } - - } - - ksort($result['rels']); - ksort($result['defs']); - - //print_r($result); - - return io_write_file(CONTENT_DIR . 'categories_encoded.dat', serialize($result)); - - //} - - return false; - - - } - - /* - - function entry_categories_print(&$lines, &$indentstack, &$result, $params) { - } -*/ - function entry_categories_list() { - if (!$string = io_load_file(CONTENT_DIR . 'categories.txt')) +class entry_index { + + var $indices = array(); + + var $_offset = 0; + + var $_chunksize = 30; + + var $_keysize = 12; + + var $_lock_file = null; + + function __construct() { + $this->_lock_file = CACHE_DIR . 'bpt.lock'; + + $this->catlist = entry_categories_list(); + + // only main index s a SBPlus (string BPlus): + // the other (other categories) are managed + // as if they were simple BPlus trees, so + // values in key,value pairs won't + // be strings but integers + // + // the integer will be the seek position + // in the SBPlus' string file + // + // they'll be loaded back with the string file + // as SBPlus trees: the string-key, string-value pair + // will be returned + + if ($oldfile = file_exists($f = INDEX_DIR . 'index-0.dat')) + $mode = 'r+b'; + else + $mode = 'w+b'; + + $this->indices [0] = new SBPlusTree(fopen($f, $mode), fopen(INDEX_DIR . 'index.strings.dat', $mode), 256, $this->_offset, $this->_chunksize, $this->_keysize); + + if ($oldfile) + $this->indices [0]->open(); + else + $this->indices [0]->startup(); + } + + function _lock_acquire($exclusive = true, $cat = 0) { + if (file_exists($this->_lock_file)) { + trigger_error("Could not acquire write lock on INDEX. " . "Didn't I told you FlatPress is not designed for concurrency, already? ;) " . "Don't worry: your entry has been saved as draft!", E_USER_WARNING); return false; - - $lines = explode("\n", trim($string)); - $idstack = array(0); - $indentstack=array(); - - - // $categories = array(0=>null); - $lastindent = 0; - $lastid = 0; - $parent = 0; - - $NEST = 0; - - foreach ($lines as $v) { - - $vt = trim($v); - - if (!$vt) continue; - - $text=''; - $indent = utils_countdashes($vt, $text); - - $val = explode(':', $text); - - $id = trim($val[1]); - $label = trim($val[0]); - - // echo "PARSE: $id:$label\n"; - if ($indent > $lastindent) { - // echo "INDENT ($indent, $id, $lastid)\n"; - $parent = $lastid; - array_push($indentstack, $lastindent); - array_push($idstack, $lastid); - $lastindent = $indent; - $NEST++; - } elseif ($indent < $lastindent) { - // echo "DEDENT ($indent)\n"; - do { - $dedent = array_pop($indentstack); - array_pop($idstack); - $NEST--; - } while ($dedent > $indent); - if ($dedent < $indent) return false; //trigger_error("failed parsing ($dedent<$indent)", E_USER_ERROR); - $parent = end($idstack); - $lastindent = $indent; - $lastid = $id; - } - - $lastid = $id; - // echo "NEST: $NEST\n"; - - - $categories[ $id ] = $parent; - + } + + // simulates atomic write by writing to a file, then moving in place + $tmp = $this->_lock_file . ".tmp"; + if (io_write_file($tmp, 'dummy')) { + if (rename($tmp, $this->_lock_file)) { + return true; } - - return $categories; - + } + + return false; } - function entry_categories_get($what=null) { - - global $fpdb; - - $categories = array(); - - if (!empty($fpdb->_categories)) { - $categories = $fpdb->_categories; - } else { + function _lock_release($cat = 0) { + if (file_exists($this->_lock_file)) { + return @unlink($this->_lock_file); + } else { + trigger_error("Lock file did not exist: ignoring (index was already unlocked.)", E_USER_NOTICE); + return 2; + } + } + + function &get_index($cat = 0) { + if (!is_numeric($cat)) + trigger_error("CAT must be an integer ($cat was given)", E_USER_ERROR); + if (!isset($this->indices [$cat])) { + $f = INDEX_DIR . 'index-' . $cat . '.dat'; + if ($oldfile = file_exists($f)) + $mode = 'r+b'; + else + $mode = 'w+b'; - $f = CONTENT_DIR . 'categories_encoded.dat'; - if (file_exists($f)) { - if ($c = io_load_file($f)) - $categories = unserialize($c); + $this->indices [$cat] = new BPlusTree(fopen($f, $mode), $this->_offset, $this->_chunksize, $this->_keysize); + if ($oldfile) + $this->indices [$cat]->open(); + else + $this->indices [$cat]->startup(); + } + return $this->indices [$cat]; + } + + function add($id, $entry, $del = array(), $update_title = true) { + $key = entry_idtokey($id); + $val = $entry ['subject']; + + if (!$this->_lock_acquire()) + return false; // we're DOOMED! + + $main = & $this->get_index(); + $seek = null; + + // title must not be updated, let's get the offset value from has_key + if (!$update_title) + $seek = $main->has_key($key, $val); + + // if seek is null, then there is no such key, and we must set it + // in the main index + if (!is_numeric($seek)) + $seek = $main->setitem($key, $val); + + // key has been set, let's set the other indices (if any), and link them + // to the title string using $seek + + if (isset($entry ['categories']) && is_array($entry ['categories'])) { + + $categories = array(); + + foreach ($entry ['categories'] as $cat) { + + // skip non-numeric special categories (such as 'draft') + if (!is_numeric($cat)) + continue; + + $categories [] = $cat; + + // traverse the full cat tree (in linearized form) + // to update categories which eventually aren't + // explicitly listed + while ($parent = $this->catlist [$cat]) { + $categories [] = $parent; + $cat = $parent; + } } + // delete any duplicate + $categories = array_unique($categories); + + foreach ($categories as $cat) { + $this_index = & $this->get_index($cat); + $this_index->setitem($key, $seek); + } } - if ($categories) { - - if ($what=='defs' || $what=='rels') - return $categories[$what]; - else - return $categories; + // if the set of indices changed, some might have to be deleted + if ($del) { + foreach ($del as $cat) { + // echo 'DEL '. $cat,"\n"; + if (!is_numeric($cat)) + continue; + $this_index = & $this->get_index($cat); + $this_index->delitem($key); + } } + + return $this->_lock_release(); + } + + function delete($id, $entry) { + $key = entry_idtokey($id); + + if (!$this->_lock_acquire()) + return false; // we're DOOMED! + + $main = & $this->get_index(); + $main->delitem($key); + + if (isset($entry ['categories']) && is_array($entry ['categories'])) { + foreach ($entry ['categories'] as $cat) { + if (!is_numeric($cat)) + continue; + $this_index = & $this->get_index($cat); + if ($this_index->has_key($key)) + $this_index->delitem($key); + } + } + + return $this->_lock_release(); + } + +} + +class entry_archives extends fs_filelister { + + var $_directory = CONTENT_DIR; + + var $_y = null; + + var $_m = null; + + var $_d = null; + + var $_count = 0; + + var $_filter = 'entry*'; + + function __construct($y, $m = null, $d = null) { + $this->_y = $y; + $this->_m = $m; + $this->_d = $d; + + $this->_directory .= "$y/"; + + if ($m) { + + $this->_directory .= "$m/"; + + if ($d) { + $this->_filter = "entry$y$m$d*"; + } + } + + return parent::__construct(); + } + + function _checkFile($directory, $file) { + $f = "$directory/$file"; + if (is_dir($f) && ctype_digit($file)) { + return 1; + } + + if (fnmatch($this->_filter . EXT, $file)) { + $id = basename($file, EXT); + $this->_count++; + array_push($this->_list, $id); + return 0; + } + } + + function getList() { + rsort($this->_list); + return parent::getList(); + } + + function getCount() { + return $this->_count; + } + +} + +// //work in progress +// class entry { + +// var $_indexer; +// var $id; + +// function entry($id, $content) { +// //$this->_indexer =& $indexer; +// } + +// function get($field) { +// $field = strtolower($field); +// if (!isset($this->$field)) { +// // if it is not set +// // tries to fetch from the database +// $arr = entry_parse($id); +// while(list($field, $val) = each($arr)) +// $this->$field = $val; + +// // if still is not set raises an error +// if (!isset($this->$field)) +// trigger_error("$field is not set", E_USER_NOTICE); +// return; + +// } + +// return $this->$field; + +// } + +// function set($field, $val) { +// $field = strtolower($field); +// $this->$field = $val; +// } + +// } + +/** + * function entry_init + * fills the global array containing the entry object + */ +function &entry_init() { + + // global $fpdb; + // $fpdb->init(); + static $entry_index = null; + + if (is_null($entry_index)) + $entry_index = new entry_index(); + + return $entry_index; +} + +function &entry_cached_index($id_cat) { + $F = INDEX_DIR . 'index-' . $id_cat . '.dat'; + + if (!file_exists($F)) { + $o = false; + } else { + $o = new entry_cached_index($id_cat); + } + + return $o; +} + +/* + * function entry_query($params=array()){ + * + * global $fpdb; + * $queryid = $fpdb->query($params); + * $fpdb->doquery($queryid); + * + * + * } + * + * function entry_hasmore() { + * global $fpdb; + * return $fpdb->hasmore(); + * + * } + * + * function entry_get() { + * $fpdb->get(); + * } + */ +function entry_keytoid($key) { + $date = substr($key, 0, 6); + $time = substr($key, 6); + return "entry{$date}-{$time}"; +} + +function entry_idtokey($id) { + return substr($id, 5, 6) . substr($id, 12); +} + +function entry_timetokey($time) { + return date('ymdHis', $time); +} + +function entry_keytotime($key) { + $arr ['y'] = substr($key, 0, 2); + $arr ['m'] = substr($key, 2, 2); + $arr ['d'] = substr($key, 4, 2); + + $arr ['H'] = substr($key, 6, 2); + $arr ['M'] = substr($key, 8, 2); + $arr ['S'] = substr($key, 10, 2); + + return mktime($arr ['H'], $arr ['M'], $arr ['S'], $arr ['m'], $arr ['d'], $arr ['y']); +} + +function entry_idtotime($id) { + $date = date_from_id($id); + return $date ['time']; +} + +function entry_list() { + trigger_error('function deprecated', E_USER_ERROR); + + $obj = & entry_init(); + + $entry_arr = $obj->getList(); + + if ($entry_arr) { + krsort($entry_arr); + return $entry_arr; + } +} + +function entry_exists($id) { + $f = entry_dir($id) . EXT; + return file_exists($f) ? $f : false; +} + +function entry_dir($id, $month_only = false) { + if (!preg_match('|^entry[0-9]{6}-[0-9]{6}$|', $id)) + return false; + $date = date_from_id($id); + if ($month_only) + $f = CONTENT_DIR . "{$date['y']}/{$date['m']}/"; + else + $f = CONTENT_DIR . "{$date['y']}/{$date['m']}/$id"; + return $f; +} + +function entry_parse($id, $raw = false) { + $f = entry_exists($id); + if (!$f) return array(); + + $fc = io_load_file($f); + + if (!$fc) + return array(); + + $arr = utils_kexplode($fc); + + // propagates the error if entry does not exist + + if (isset($arr ['categories']) && // fix to bad old behaviour: + (trim($arr ['categories']) != '')) { + + $cats = (array) explode(',', $arr ['categories']); + $arr ['categories'] = (array) $cats; + } else + $arr ['categories'] = array(); + + // if (!is_array($arr['categories'])) die(); + + if (!isset($arr ['AUTHOR'])) { + global $fp_config; + $arr ['AUTHOR'] = $fp_config ['general'] ['author']; } - /** - - flags are actually special categories - which are usually hidden. - - they can be set when editing your entries - to let flatpress perform special actions - - draft: Draft entry (hidden, awaiting publication) - static: Static entry (allows saving an alias, so you can reach it with - ?page=myentry) - commslock: Comments locked (comments disallowed for this entry) - - - */ + if ($raw) + return $arr; + return $arr; +} + +/** + * function entry_get_comments + * + * @param + * string id entry id + * @param + * array entry entry content array by ref; 'commentcount' field is added to the array + * + * @return object comment_indexer as reference + * + */ +function &entry_get_comments($id, &$count) { + $obj = new comment_indexer($id); - function entry_flags_get() { - - return array( - 'draft', - //'static', - 'commslock' - ); + $count = count($obj->getList()); + + return $obj; +} + +function entry_categories_encode($cat_file) { + + // if ($string = io_load_file(CONTENT_DIR . 'categories.txt')) { + $lines = explode("\n", trim($cat_file)); + $idstack = $result = $indentstack = array(); + + while (!empty($lines)) { + $v = array_pop($lines); - } - - // @TODO : check against schema ? - function entry_prepare(&$entry) { // prepare for serialization - global $post; + $vt = trim($v); - // fill in missing value - if (!isset($entry['date'])) { - $entry['date']=date_time(); - } - - // import into global scope - $post = $entry; - - // apply *_pre filters - $entry['content'] = apply_filters('content_save_pre', $entry['content']); - $entry['subject'] = apply_filters('title_save_pre', $entry['subject']); - - - // prepare for serialization - if (isset($entry['categories'])) { - - if (!is_array($entry['categories'])) { - trigger_error("Expected 'categories' to be an array, found " - . gettype($entry['categories']), E_USER_WARNING); - $entry['categories'] = array(); + if ($vt) { + + $text = ''; + $indent = utils_countdashes($vt, $text); + + $val = explode(':', $text); + + $id = trim($val [1]); + $label = trim($val [0]); + + // IDs must be strictly positive + + if ($label && $id <= 0) + return -1; + + if (empty($indentstack)) { + array_push($indentstack, $indent); + array_push($idstack, $id); + $indent_old = $indent; + } else { + $indent_old = end($indentstack); } - - } else { $entry['categories'] = array(); } - - - - return $entry; + + if ($indent < $indent_old) { + array_push($indentstack, $indent); + array_push($idstack, $id); + } elseif ($indent > $indent_old) { + $idstack = array( + $id + ); + $indentstack = array( + $indent + ); + } else { + array_pop($idstack); + $idstack = array( + $id + ); + } + + $result ['rels'] [$id] = $idstack; + $result ['defs'] [$id] = $label; + } } + + ksort($result ['rels']); + ksort($result ['defs']); + + // print_r($result); + + return io_write_file(CONTENT_DIR . 'categories_encoded.dat', serialize($result)); + + // } + + return false; +} - /** - * - * @param array entry contents - * @param string|null entry id, null if can be deducted from the date field of $entry; - * defaults to null - * - * @param bool updates entry index; defaults to true - * - * - * @return integer -1 failure while storing preliminar draft, abort. Index not touched. - * -2 index updated succesfully, but draft doesn't exist anymore - * (should never happen!) OR - * failure while trying to move draft to entry path, draft does not exist anymore - * index not touched - * -3 error while moving draft still exists, index written succesfully but rolled back - * -4 failure while saving to index, aborted (draft still exists) - * - * +/* + * + * function entry_categories_print(&$lines, &$indentstack, &$result, $params) { + * + * + * } + * + */ +function entry_categories_list() { + if (!$string = io_load_file(CONTENT_DIR . 'categories.txt')) + return false; + + $lines = explode("\n", trim($string)); + $idstack = array( + 0 + ); + $indentstack = array(); + + // $categories = array(0=>null); + $lastindent = 0; + $lastid = 0; + $parent = 0; + + $NEST = 0; + + foreach ($lines as $v) { + + $vt = trim($v); + + if (!$vt) + continue; + + $text = ''; + $indent = utils_countdashes($vt, $text); + + $val = explode(':', $text); + + $id = trim($val [1]); + $label = trim($val [0]); + + // echo "PARSE: $id:$label\n"; + if ($indent > $lastindent) { + // echo "INDENT ($indent, $id, $lastid)\n"; + $parent = $lastid; + array_push($indentstack, $lastindent); + array_push($idstack, $lastid); + $lastindent = $indent; + $NEST++; + } elseif ($indent < $lastindent) { + // echo "DEDENT ($indent)\n"; + do { + $dedent = array_pop($indentstack); + array_pop($idstack); + $NEST--; + } while ($dedent > $indent); + if ($dedent < $indent) + return false; // trigger_error("failed parsing ($dedent<$indent)", E_USER_ERROR); + $parent = end($idstack); + $lastindent = $indent; + $lastid = $id; + } + + $lastid = $id; + // echo "NEST: $NEST\n"; + + $categories [$id] = $parent; + } + + return $categories; +} + +function entry_categories_get($what = null) { + global $fpdb; + + $categories = array(); + + if (!empty($fpdb->_categories)) { + $categories = $fpdb->_categories; + } else { + + $f = CONTENT_DIR . 'categories_encoded.dat'; + if (file_exists($f)) { + if ($c = io_load_file($f)) + $categories = unserialize($c); + } + } + + if ($categories) { + + if ($what == 'defs' || $what == 'rels') + return $categories [$what]; + else + return $categories; + } + return array(); +} + +/** + * flags are actually special categories + * which are usually hidden. + * + * they can be set when editing your entries + * to let flatpress perform special actions + * + * draft: Draft entry (hidden, awaiting publication) + * static: Static entry (allows saving an alias, so you can reach it with + * ?page=myentry) + * commslock: Comments locked (comments disallowed for this entry) + */ +function entry_flags_get() { + return array( + 'draft', + // 'static', + 'commslock' + ); +} + +// @TODO : check against schema ? +function entry_prepare(&$entry) { // prepare for serialization + global $post; + + // fill in missing value + if (!isset($entry ['date'])) { + $entry ['date'] = date_time(); + } + + // import into global scope + $post = $entry; + + // apply *_pre filters + $entry ['content'] = apply_filters('content_save_pre', $entry ['content']); + $entry ['subject'] = apply_filters('title_save_pre', $entry ['subject']); + + // prepare for serialization + if (isset($entry ['categories'])) { + + if (!is_array($entry ['categories'])) { + trigger_error("Expected 'categories' to be an array, found " . gettype($entry ['categories']), E_USER_WARNING); + $entry ['categories'] = array(); + } + } else { + $entry ['categories'] = array(); + } + + return $entry; +} + +/** + * + * @param + * array entry contents + * @param + * string|null entry id, null if can be deducted from the date field of $entry; + * defaults to null + * + * @param + * bool updates entry index; defaults to true + * + * + * @return integer -1 failure while storing preliminar draft, abort. Index not touched. + * -2 index updated succesfully, but draft doesn't exist anymore + * (should never happen!) OR + * failure while trying to move draft to entry path, draft does not exist anymore + * index not touched + * -3 error while moving draft still exists, index written succesfully but rolled back + * -4 failure while saving to index, aborted (draft still exists) + * + * + */ +function entry_save($entry, $id = null, $update_index = true) { + + // PHASE 1 : prepare entry + if (!$id) { + if (!@$entry ['date']) + $entry ['date'] = date_time(); + $id = bdb_idfromtime(BDB_ENTRY, $entry ['date']); + } + + // PHASE 2 : Store + + // secure data as DRAFT + // (entry is also implicitly entry_prepare()'d here) + $ret = draft_save($entry, $id); + do_action('publish_post', $id, $entry); + + if ($ret === false) { + return -1; // FAILURE: ABORT + } + + // PHASE 3 : Update index + $delete_cats = array(); + $all_cats = @$entry ['categories']; + $update_title = true; + if ($old_entry = entry_parse($id)) { + if ($all_cats) { + $delete_cats = array_diff($old_entry ['categories'], $all_cats); + } + $all_cats = $all_cats ? array_merge($all_cats, $old_entry ['categories']) : $old_entry ['categories']; + $update_title = $entry ['subject'] != $old_entry ['subject']; + } + + /* + * echo 'old'; + * print_r($old_entry['categories']); + * echo 'new'; + * print_r($entry['categories']); + * echo 'del'; + * print_r($delete_cats); + * echo 'all'; + * print_r($all_cats); */ + + $INDEX = & entry_init(); + $ok = ($update_index) ? $INDEX->add($id, $entry, $delete_cats, $update_title) : true; + + // PHASE 4 : index updated; let's move back the entry + if ($ok) { - function entry_save($entry, $id=null, $update_index = true) { - - // PHASE 1 : prepare entry - if (!$id) { - if (!@$entry['date']) $entry['date'] = date_time(); - $id = bdb_idfromtime(BDB_ENTRY, $entry['date']); - } - - - // PHASE 2 : Store - - // secure data as DRAFT - // (entry is also implicitly entry_prepare()'d here) - $ret = draft_save($entry, $id); - do_action('publish_post', $id, $entry); - - if ($ret === false) { - return -1; // FAILURE: ABORT - } - - - // PHASE 3 : Update index - $delete_cats = array(); - $all_cats = @$entry['categories']; - $update_title = true; - if ($old_entry = entry_parse($id)) { - if ($all_cats) { - $delete_cats = array_diff($old_entry['categories'], $all_cats); + $entryd = entry_dir($id, true); + $entryf = $entryd . $id . EXT; + $draftf = draft_exists($id); + if ($draftf === false) { // this should never happen! + if ($update_index) { + $INDEX->delete($id, $all_cats); } - $all_cats = $all_cats? array_merge($all_cats, $old_entry['categories']) : $old_entry['categories']; - $update_title = $entry['subject'] != $old_entry['subject']; - } - - /* - echo 'old'; - print_r($old_entry['categories']); - echo 'new'; - print_r($entry['categories']); - echo 'del'; - print_r($delete_cats); - echo 'all'; - print_r($all_cats); - */ - - $INDEX =& entry_init(); - $ok = ($update_index) ? $INDEX->add($id, $entry, $delete_cats, $update_title) : true; - - // PHASE 4 : index updated; let's move back the entry - if ($ok) { - - $entryd = entry_dir($id, true); - $entryf = $entryd.$id.EXT; - $draftf = draft_exists($id); - if ($draftf === false) { // this should never happen! + return -2; + } + + fs_delete($entryf); + fs_mkdir($entryd); + $ret = rename($draftf, $entryf); + + if (!$ret) { + if (draft_exists($id)) { + // rollback changes in the index + // (keep the draft file) if ($update_index) { - $INDEX->delete($id, $all_cats); + $INDEX->delete($id, $all_cats); } + return -3; + } else { return -2; } - - fs_delete($entryf); - fs_mkdir($entryd); - $ret = rename($draftf, $entryf); + } else { + // SUCCESS : delete draft, move comments along + draft_to_entry($id); + return $id; + } + } + return -4; +} - if (!$ret) { - if (draft_exists($id)) { - // rollback changes in the index - // (keep the draft file) - if ($update_index) { - $INDEX->delete($id, $all_cats); - } - return -3; - } else { - return -2; - } - } else { - // SUCCESS : delete draft, move comments along - draft_to_entry($id); - return $id; - } - - } - return -4; - - } +function entry_delete($id) { + if (!$f = entry_exists($id)) + return; + + /* + * $d = bdb_idtofile($id,BDB_COMMENT); + * fs_delete_recursive("$d"); + * + * // thanks to cimangi for noticing this + * $f = dirname($d) . '/view_counter' .EXT; + * fs_delete($f); + * + * + * $f = bdb_idtofile($id); + */ + + $d = entry_dir($id); + fs_delete_recursive($d); + + $obj = & entry_init(); + $obj->delete($id, entry_parse($id)); + + do_action('delete_post', $id); + + return fs_delete($f); +} - - function entry_delete($id) { - - if ( ! $f = entry_exists($id) ) - return; - - - /* - $d = bdb_idtofile($id,BDB_COMMENT); - fs_delete_recursive("$d"); - - // thanks to cimangi for noticing this - $f = dirname($d) . '/view_counter' .EXT; - fs_delete($f); - - - $f = bdb_idtofile($id); - */ - - $d = entry_dir($id); - fs_delete_recursive($d); - - $obj =& entry_init(); - $obj->delete($id, entry_parse($id)); - - do_action('delete_post', $id); - - return fs_delete($f); - } - - function entry_purge_cache() { - $obj =& entry_init(); - $obj->purge(); - } - //add_action('init', +function entry_purge_cache() { + $obj = & entry_init(); + $obj->purge(); +} +// add_action('init', ?> diff --git a/fp-includes/core/core.utils.php b/fp-includes/core/core.utils.php index 3bc668c..101b389 100644 --- a/fp-includes/core/core.utils.php +++ b/fp-includes/core/core.utils.php @@ -1,458 +1,442 @@ $string - keys were supposed to be UPPERCASE but \"$k\" was found; file may be corrupted - or in an expected format.
- Some SimplePHPBlog files may raise this error: set DUMB_MODE_ENABLED - to true in your defaults.php to force parsing of the offending keys.", - E_USER_WARNING); - */ - continue; - } - - $arr[strtolower($k)] = strtok($delim); + $k = strtolower(strtok($string, $delim)); + $arr [$k] = strtok($delim); + while (($k = strtok($delim)) !== false) { + if ($keyupper && !preg_match('/[A-Z-_]/', $k)) { + /* + * trigger_error("Failed parsing
$string
+ * keys were supposed to be UPPERCASE but \"$k\" was found; file may be corrupted + * or in an expected format.
+ * Some SimplePHPBlog files may raise this error: set DUMB_MODE_ENABLED + * to true in your defaults.php to force parsing of the offending keys.", + * E_USER_WARNING); + */ + continue; } - return $arr; + $arr [strtolower($k)] = strtok($delim); } + return $arr; +} - /* - function utils_newkexplode($string, $delim='|') { - - $arr = array(); - - $lastoffset = $offset = 0; - $len = strlen($string); - - while ($lastoffset<$len) { - $offset = strpos($string, $delim, $lastoffset); - $key = substr($string, $lastoffset, $offset-$lastoffset); - //echo 'parsing key: ', $key, $offset, chr(10); - - $lastoffset = $offset + 1; - - if (!ctype_upper($key)) - trigger_error("Failed parsing \"$string\" - keys were supposed to be UPPERCASE", E_USER_ERROR); - - $offset = strpos($string, $delim, $lastoffset); +/* + * function utils_newkexplode($string, $delim='|') { + * + * $arr = array(); + * + * $lastoffset = $offset = 0; + * $len = strlen($string); + * + * while ($lastoffset<$len) { + * $offset = strpos($string, $delim, $lastoffset); + * $key = substr($string, $lastoffset, $offset-$lastoffset); + * //echo 'parsing key: ', $key, $offset, chr(10); + * + * $lastoffset = $offset + 1; + * + * if (!ctype_upper($key)) + * trigger_error("Failed parsing \"$string\" + * keys were supposed to be UPPERCASE", E_USER_ERROR); + * + * $offset = strpos($string, $delim, $lastoffset); + * + * if ($offset===false) + * $offset = $len; + * + * $val = substr($string, $lastoffset, $offset-$lastoffset); + * + * //echo 'parsing value ', $val, $offset, chr(10); + * + * $lastoffset = $offset + 1; + * + * $arr[$key] = $val; + * + * } + * return $arr; + * + * } + */ - if ($offset===false) - $offset = $len; +// function prototype: +// array utils_kimplode(string $string, string $delim='|') - $val = substr($string, $lastoffset, $offset-$lastoffset); - - //echo 'parsing value ', $val, $offset, chr(10); - - $lastoffset = $offset + 1; - - $arr[$key] = $val; - - } - return $arr; - - }*/ - - - // function prototype: - // array utils_kimplode(string $string, string $delim='|') - - // explodes a string into an array by the given delimiter; - // delimiter defaults to pipe ('|'). - // the string must be formatted as in: - // key1|value1|key2|value2 , etc. - // the array will look like - // $arr['key1'] = 'value1'; $arr['key2'] = 'value2'; etc. - - function utils_kimplode($arr, $delim='|') { - - $string = ""; - foreach ($arr as $k => $val) { - if ($val) - $string .= strtoupper($k) . $delim . ($val) . $delim; - } - return $string; +// explodes a string into an array by the given delimiter; +// delimiter defaults to pipe ('|'). +// the string must be formatted as in: +// key1|value1|key2|value2 , etc. +// the array will look like +// $arr['key1'] = 'value1'; $arr['key2'] = 'value2'; etc. +function utils_kimplode($arr, $delim = '|') { + $string = ""; + foreach ($arr as $k => $val) { + if ($val) + $string .= strtoupper($k) . $delim . ($val) . $delim; } + return $string; +} + +/** + * + * @todo send mail to admin + */ +function &utils_explode_recursive($array, &$string, $rdelim, $ldelim = '', $outerldelim = '', $outerrdelim = '') { + $string .= $outerldelim; - /** - * @todo send mail to admin - */ - - - function &utils_explode_recursive($array, &$string, $rdelim, $ldelim='', $outerldelim='', $outerrdelim='') { - - $string .= $outerldelim; - - while ($val = array_shift($array)) { - - $string .= $rdelim; - if (is_array($val)) { - $string .= utils_explode_recursive($val, $string, $rdelim, $ldelim, $outerldelim, $outerrdelim); - } else { - $string .= $val; - } - - $string .= $ldelim; - - } - - $string .= $outerrdelim; - - } - - - - - - function utils_validateinput($str) { + while ($val = array_shift($array)) { - if (preg_match('/[^a-z0-9\-_]/i',$str)){ - trigger_error("String \"$str\" is not a valid input", E_USER_ERROR); - //return false; - } else - return true; - } - - function utils_cut_string($str,$maxc) { - $car = strlen($str); - if($car > $maxc) { - return substr($str, 0, $maxc)."..."; + $string .= $rdelim; + if (is_array($val)) { + $string .= utils_explode_recursive($val, $string, $rdelim, $ldelim, $outerldelim, $outerrdelim); } else { - return $str; - } - } - - - function utils_status_header($status) { - - switch ($status) { - case 301: - header("HTTP/1.1 301 Moved Permanently"); - break; - case 403: - header("HTTP/1.1 403 Forbidden"); - break; - case 404: - header("HTTP/1.1 404 Not Found"); - break; - - } - - } - - // code from php.net ;) - // defaults to index.php ;) - function utils_redirect($location="", $absolute_path=false, $red_type=null) { - - if (!$absolute_path) - $location = BLOG_BASEURL . $location; - - if ( function_exists('wp_redirect') ) { - wp_redirect($location); - } else { - header("Location: $location"); + $string .= $val; } - exit(); - + $string .= $ldelim; } + $string .= $outerrdelim; +} + +function utils_validateinput($str) { + if (preg_match('/[^a-z0-9\-_]/i', $str)) { + trigger_error("String \"$str\" is not a valid input", E_USER_ERROR); + // return false; + } else + return true; +} + +function utils_cut_string($str, $maxc) { + $car = strlen($str); + if ($car > $maxc) { + return substr($str, 0, $maxc) . "..."; + } else { + return $str; + } +} + +function utils_status_header($status) { + switch ($status) { + case 301: + header("HTTP/1.1 301 Moved Permanently"); + break; + case 403: + header("HTTP/1.1 403 Forbidden"); + break; + case 404: + header("HTTP/1.1 404 Not Found"); + break; + } +} + +// code from php.net ;) +// defaults to index.php ;) +function utils_redirect($location = "", $absolute_path = false, $red_type = null) { + if (!$absolute_path) + $location = BLOG_BASEURL . $location; - /* - * utils_geturlstring() - * - * @return string complete url string as displayed in the browser - * - */ - - function utils_geturlstring() { - $str = BLOG_BASEURL . $_SERVER['PHP_SELF']; - if ($_SERVER['QUERY_STRING']) - $str .='?'.$_SERVER['QUERY_STRING']; - return $str; + if (function_exists('wp_redirect')) { + wp_redirect($location); + } else { + header("Location: $location"); } - // custom array_merge: - // pads the second array to match the length of the first - // this can be improved, anyway for now I'd just - // do a quick & dirty solution :) - function utils_array_merge($arr1, $arr2) { - - $len=count($arr1[0]); - - foreach($arr2 as $k=>$v) - $arr2[$k]=array_pad((Array) $v, $len, null); - - return array_merge($arr1, $arr2); + exit(); +} + +/* + * utils_geturlstring() + * + * @return string complete url string as displayed in the browser + * + */ +function utils_geturlstring() { + $str = BLOG_BASEURL . $_SERVER ['PHP_SELF']; + if ($_SERVER ['QUERY_STRING']) + $str .= '?' . $_SERVER ['QUERY_STRING']; + return $str; +} + +// custom array_merge: +// pads the second array to match the length of the first +// this can be improved, anyway for now I'd just +// do a quick & dirty solution :) +function utils_array_merge($arr1, $arr2) { + $len = count($arr1 [0]); + + foreach ($arr2 as $k => $v) + $arr2 [$k] = array_pad((array) $v, $len, null); + + return array_merge($arr1, $arr2); +} + +/* + * Simple function to replicate PHP 5 behaviour + */ +function utils_microtime() { + list ($usec, $sec) = explode(" ", microtime()); + return ((float) $usec + (float) $sec); +} + +function utils_countdashes($string, &$rest) { + trim($string); + $i = 0; + while ($string {$i} == '-') { + $i++; } + if ($i) + $rest = substr($string, $i); + else + $rest = $string; + + return $i; +} - - /* - * Simple function to replicate PHP 5 behaviour - */ - function utils_microtime() - { - list($usec, $sec) = explode(" ", microtime()); - return ((float)$usec + (float)$sec); - } - - function utils_countdashes($string, &$rest) { - trim($string); - $i = 0; - while ($string{$i} == '-') { - $i++; - } - if ($i) - $rest = substr($string, $i); - else $rest = $string; - - return $i; - - - } - - function utils_mail($from, $subject, $message, $headers = '') { - global $fp_config; - if( $headers == '' ) { - $headers = "MIME-Version: 1.0\n" . - "From: " . $from . "\n" . - "Content-Type: text/plain; charset=\"" . $fp_config['general']['charset'] . "\"\n"; - } - - return mail($fp_config['general']['email'], $subject, $message, $headers); +function utils_mail($from, $subject, $message, $headers = '') { + global $fp_config; + if ($headers == '') { + $headers = "MIME-Version: 1.0\n" . "From: " . $from . "\n" . "Content-Type: text/plain; charset=\"" . $fp_config ['general'] ['charset'] . "\"\n"; } + return mail($fp_config ['general'] ['email'], $subject, $message, $headers); +} + /* * props: http://crisp.tweakblogs.net/blog/2031 */ - function utils_validateIPv4($IP) { - return $IP == long2ip(ip2long($IP)); - } - - function utils_validateIPv6($IP) { - // fast exit for localhost - if (strlen($IP) < 3) - return $IP == '::'; - - // Check if part is in IPv4 format - if (strpos($IP, '.')) - { - $lastcolon = strrpos($IP, ':'); - if (!($lastcolon && validateIPv4(substr($IP, $lastcolon + 1)))) - return false; - - // replace IPv4 part with dummy - $IP = substr($IP, 0, $lastcolon) . ':0:0'; - } - - // check uncompressed - if (strpos($IP, '::') === false) - { - return preg_match('/^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i', $IP); - } - - // check colon-count for compressed format - if (substr_count($IP, ':') < 8) - { - return preg_match('/^(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?$/i', $IP); - } - - return false; - } +function utils_validateIPv4($IP) { + return $IP == long2ip(ip2long($IP)); +} - // get client IP - function utils_ipget() { +function utils_validateIPv6($IP) { + // fast exit for localhost + if (strlen($IP) < 3) + return $IP == '::'; + + // Check if part is in IPv4 format + if (strpos($IP, '.')) { + $lastcolon = strrpos($IP, ':'); + if (!($lastcolon && validateIPv4(substr($IP, $lastcolon + 1)))) + return false; - $ip = ''; - - if ( !empty ( $_SERVER[ 'HTTP_CLIENT_IP' ] ) ) { - $ip = $_SERVER[ 'HTTP_CLIENT_IP' ]; - } - elseif ( !empty ( $_SERVER[ 'HTTP_X_FORWARDED_FOR' ] ) ) { - $ip = $_SERVER[ 'HTTP_X_FORWARDED_FOR' ]; - } - elseif ( !empty ( $_SERVER[ 'REMOTE_ADDR' ] ) ) { - $ip = $_SERVER[ 'REMOTE_ADDR' ]; - } - elseif ( getenv( "HTTP_CLIENT_IP" ) ) { - $ip = getenv( "HTTP_CLIENT_IP" ); - } - elseif ( getenv( "HTTP_X_FORWARDED_FOR" ) ) { - $ip = getenv( "HTTP_X_FORWARDED_FOR" ); - } - elseif ( getenv( "REMOTE_ADDR") ) { - $ip = getenv( "REMOTE_ADDR" ); - } - - if (utils_validateIPv4($ip) || utils_validateIPv6($ip)) { - return $ip; - } else { - return ''; - } - - + // replace IPv4 part with dummy + $IP = substr($IP, 0, $lastcolon) . ':0:0'; } - - function utils_nocache_headers() { - @ header('Expires: Wed, 11 Jan 1984 05:00:00 GMT'); - @ header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - @ header('Cache-Control: no-cache, must-revalidate, max-age=0'); - @ header('Pragma: no-cache'); + + // check uncompressed + if (strpos($IP, '::') === false) { + return preg_match('/^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i', $IP); } + + // check colon-count for compressed format + if (substr_count($IP, ':') < 8) { + return preg_match('/^(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?$/i', $IP); + } + + return false; +} + +// get client IP +function utils_ipget() { + $ip = ''; + + if (!empty($_SERVER ['HTTP_CLIENT_IP'])) { + $ip = $_SERVER ['HTTP_CLIENT_IP']; + } elseif (!empty($_SERVER ['HTTP_X_FORWARDED_FOR'])) { + $ip = $_SERVER ['HTTP_X_FORWARDED_FOR']; + } elseif (!empty($_SERVER ['REMOTE_ADDR'])) { + $ip = $_SERVER ['REMOTE_ADDR']; + } elseif (getenv("HTTP_CLIENT_IP")) { + $ip = getenv("HTTP_CLIENT_IP"); + } elseif (getenv("HTTP_X_FORWARDED_FOR")) { + $ip = getenv("HTTP_X_FORWARDED_FOR"); + } elseif (getenv("REMOTE_ADDR")) { + $ip = getenv("REMOTE_ADDR"); + } + + if (utils_validateIPv4($ip) || utils_validateIPv6($ip)) { + return $ip; + } else { + return ''; + } +} + +function utils_nocache_headers() { + @ header('Expires: Wed, 11 Jan 1984 05:00:00 GMT'); + @ header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + @ header('Cache-Control: no-cache, must-revalidate, max-age=0'); + @ header('Pragma: no-cache'); +} // from http://nadeausoftware.com/articles/2007/06/php_tip_how_get_web_page_using_curl // code under OSI BSD /** - * Get a web file (HTML, XHTML, XML, image, etc.) from a URL. Return an + * Get a web file (HTML, XHTML, XML, image, etc.) from a URL. + * Return an * array containing the HTTP server response header fields and content. */ function utils_geturl($url) { /* - if (ini_get('allow_url_fopen')) { - return array('content' => io_load_file($url)); - } - */ + * if (ini_get('allow_url_fopen')) { + * return array('content' => io_load_file($url)); + * } + */ if (!function_exists('curl_init')) { trigger_error('curl extension is not installed'); return array(); } - - $options = array( - CURLOPT_RETURNTRANSFER => true, // return web page - CURLOPT_HEADER => false, // don't return headers - CURLOPT_FOLLOWLOCATION => false, // don't follow redirects - CURLOPT_ENCODING => "", // handle all encodings - CURLOPT_USERAGENT => "spider", // who am i - CURLOPT_AUTOREFERER => true, // set referer on redirect - CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect - CURLOPT_TIMEOUT => 120, // timeout on response - CURLOPT_MAXREDIRS => 10, // stop after 10 redirects - ); - - $ch = curl_init( $url ); - curl_setopt_array( $ch, $options ); - $content = curl_exec( $ch ); - $err = curl_errno( $ch ); - $errmsg = curl_error( $ch ); - $header = curl_getinfo( $ch ); - curl_close( $ch ); - - $header['errno'] = $err; - $header['errmsg'] = $errmsg; - $header['content'] = $content; - return $header; + + $options = array( + CURLOPT_RETURNTRANSFER => true, // return web page + CURLOPT_HEADER => false, // don't return headers + CURLOPT_FOLLOWLOCATION => false, // don't follow redirects + CURLOPT_ENCODING => "", // handle all encodings + CURLOPT_USERAGENT => "spider", // who am i + CURLOPT_AUTOREFERER => true, // set referer on redirect + CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect + CURLOPT_TIMEOUT => 120, // timeout on response + CURLOPT_MAXREDIRS => 10 // stop after 10 redirects + ); + + $ch = curl_init($url); + curl_setopt_array($ch, $options); + $content = curl_exec($ch); + $err = curl_errno($ch); + $errmsg = curl_error($ch); + $header = curl_getinfo($ch); + curl_close($ch); + + $header ['errno'] = $err; + $header ['errmsg'] = $errmsg; + $header ['content'] = $content; + return $header; } - - - function utils_checksmarty() { - - if (!file_exists(SMARTY_DIR . 'Smarty.class.php')) { +function utils_checksmarty() { + if (!file_exists(SMARTY_DIR . 'Smarty.class.php')) { $err = <<http://smarty.php.net; you will probably need SmartyValidate as well; unpack them to fp-includes/core/smarty: please do not overwrite files in fp-includes/core/smarty/plugins/ ERR; trigger_error($err, E_USER_ERROR); - } + } +} + +function fplog($str) { + if (!defined('DEBUG_MODE')) + echo "\n[DEBUG] $str \n"; +} + +/** + * Shift an element with its key off the beginning of array. + * Just like array_shift(), but for an associative array. + * + * @param array $arr + * The input array + * @return unknown the shifted value, or NULL if array is empty or is not an array + */ +function utils_array_kshift(&$arr) { + list ($k) = array_keys($arr); + $r = array( + $k => $arr [$k] + ); + unset($arr [$k]); + return $r; +} - } - - - function fplog($str) { - if(!defined('DEBUG_MODE')) - echo "\n[DEBUG] $str \n"; - } - ?> diff --git a/fp-plugins/calendar/plugin.calendar.php b/fp-plugins/calendar/plugin.calendar.php index 4e36596..86a3cc0 100755 --- a/fp-plugins/calendar/plugin.calendar.php +++ b/fp-plugins/calendar/plugin.calendar.php @@ -1,95 +1,100 @@ . See http://diveintomark.org/archives/2002/07/03 - // PHP7 compatibility: Since $pn is never passed, we do not need to create "previous" and "next" elements. - // Commented out to prevent deprecated each() function from being executed. +// PHP Calendar (version 2.3), written by Keith Devens +// http://keithdevens.com/software/php_calendar +// see example at http://keithdevens.com/weblog +// License: http://keithdevens.com/software/license +function generate_calendar($year, $month, $days = array(), $day_name_length = 3, $month_href = NULL, $first_day = 0, $pn = array()) { + $first_of_month = gmmktime(0, 0, 0, $month, 1, $year); + // remember that mktime will automatically correct if invalid dates are entered + // for instance, mktime(0,0,0,12,32,1997) will be the date for Jan 1, 1998 + // this provides a built in "rounding" feature to generate_calendar() + + $day_names = array(); // generate all the day names according to the current locale + for($n = 0, $t = (3 + $first_day) * 86400; $n < 7; $n++, $t += 86400) // January 4, 1970 was a Sunday + $day_names [$n] = ucfirst(date_strformat('%A', $t)); // %A means full textual day name + + list ($month, $year, $month_name, $weekday) = explode(',', date_strformat('%m,%Y,%B,%w', $first_of_month)); + $weekday = ($weekday + 7 - $first_day) % 7; // adjust for $first_day + $title = htmlentities(ucfirst($month_name)) . ' ' . $year; // note that some locales don't capitalize month and day names + + // Begin calendar. Uses a real . See http://diveintomark.org/archives/2002/07/03 + + // PHP7 compatibility: Since $pn is never passed, we do not need to create "previous" and "next" elements. $p = ''; $n = ''; -/* - @list($p, $pl) = each($pn); @list($n, $nl) = each($pn); #previous and next links, if applicable - if($p) $p = ''.($pl ? ''.$p.'' : $p).' '; - if($n) $n = ' '.($nl ? ''.$n.'' : $n).''; -*/ - $calendar = ''."\n". - '\n"; - - if($day_name_length){ #if the day names should be shown ($day_name_length > 0) - #if day_name_length is >3, the full name of the day will be printed - foreach($day_names as $d) - $calendar .= ''; + // Commented out to prevent deprecated each() function from being executed. + // @list($p, $pl) = each($pn); @list($n, $nl) = each($pn); #previous and next links, if applicable + // if($p) $p = ''.($pl ? ''.$p.'' : $p).' '; + // if($n) $n = ' '.($nl ? ''.$n.'' : $n).''; + + $calendar = '
'.$p.($month_href ? ''.$title.'' : $title).$n."
'.htmlentities($day_name_length < 4 ? substr($d,0,$day_name_length) : $d).'
' . "\n" . '\n"; + + if ($day_name_length) { // if the day names should be shown ($day_name_length > 0) + // if day_name_length is >3, the full name of the day will be printed + foreach ($day_names as $d) + $calendar .= ''; $calendar .= "\n"; } - - if($weekday > 0) $calendar .= ''; #initial 'empty' days - for($day=1,$days_in_month=gmdate('t',$first_of_month); $day<=$days_in_month; $day++,$weekday++){ - if($weekday == 7){ - $weekday = 0; #start a new week + + if ($weekday > 0) + $calendar .= ''; // initial 'empty' days + for($day = 1, $days_in_month = gmdate('t', $first_of_month); $day <= $days_in_month; $day++, $weekday++) { + if ($weekday == 7) { + $weekday = 0; // start a new week $calendar .= "\n"; } - if(isset($days[$day]) and is_array($days[$day])){ - @list($link, $classes, $content) = $days[$day]; - if(is_null($content)) $content = $day; - $calendar .= '' : '>'). - ($link ? ''.$content.'' : $content).''; - } - else $calendar .= ""; + if (isset($days [$day]) and is_array($days [$day])) { + @list ($link, $classes, $content) = $days [$day]; + if (is_null($content)) + $content = $day; + $calendar .= '' : '>') . ($link ? '' . $content . '' : $content) . ''; + } else + $calendar .= ""; } - if($weekday != 7) $calendar .= ''; #remaining "empty" days - - return $calendar."\n
' . $p . ($month_href ? '' . $title . '' : $title) . $n . "
' . htmlentities($day_name_length < 4 ? substr($d, 0, $day_name_length) : $d) . '
  
$day$day 
\n"; + if ($weekday != 7) + $calendar .= ' '; // remaining "empty" days + + return $calendar . "\n\n"; } function plugin_calendar_widget() { - global $fp_params; - $y = isset($fp_params['y'])? $fp_params['y'] : date('y'); - $m = isset($fp_params['m'])? $fp_params['m'] : date('m'); - + $y = isset($fp_params ['y']) ? $fp_params ['y'] : date('y'); + $m = isset($fp_params ['m']) ? $fp_params ['m'] : date('m'); + global $fpdb; - $q = new FPDB_Query(array('fullparse'=>false,'y'=>$y,'m'=>$m, 'count' => -1), null); - + $q = new FPDB_Query(array( + 'fullparse' => false, + 'y' => $y, + 'm' => $m, + 'count' => -1 + ), null); $days = array(); while ($q->hasmore($queryId)) { - list($id, $entry) = $q->getEntry($queryId); + list ($id, $entry) = $q->getEntry($queryId); $date = date_from_id($id); - $d = (int)$date['d']; - - $days[$d] = array(get_day_link($y, $m, str_pad($d, 2, '0', STR_PAD_LEFT)), 'linked-day'); + $d = (int) $date ['d']; + $days [$d] = array( + get_day_link($y, $m, str_pad($d, 2, '0', STR_PAD_LEFT)), + 'linked-day' + ); $count++; } @@ -99,8 +104,8 @@ function plugin_calendar_widget() { $lang = lang_load('plugin:calendar'); $widget = array(); - $widget['subject'] = $lang['plugin']['calendar']['subject']; - $widget['content'] = ''; + $widget ['subject'] = $lang ['plugin'] ['calendar'] ['subject']; + $widget ['content'] = ''; return $widget; }