lockfile again

This commit is contained in:
Tim Bendt
2025-11-26 11:50:55 -05:00
parent af3c23cb6e
commit 6ceecaa69e
4461 changed files with 641349 additions and 10 deletions

View File

@@ -0,0 +1,57 @@
<?php
namespace PhpRbac;
use \Jf;
/**
* @file
* Provides NIST Level 2 Standard Role Based Access Control functionality
*
* @defgroup phprbac Rbac Functionality
* @{
* Documentation for all PhpRbac related functionality.
*/
class Rbac
{
public function __construct($unit_test = '')
{
if ((string) $unit_test === 'unit_test') {
require_once dirname(dirname(__DIR__)) . '/tests/database/database.config';
} else {
require_once dirname(dirname(__DIR__)) . '/database/database.config';
}
require_once 'core/lib/Jf.php';
$this->Permissions = Jf::$Rbac->Permissions;
$this->Roles = Jf::$Rbac->Roles;
$this->Users = Jf::$Rbac->Users;
}
public function assign($role, $permission)
{
return Jf::$Rbac->assign($role, $permission);
}
public function check($permission, $user_id)
{
return Jf::$Rbac->check($permission, $user_id);
}
public function enforce($permission, $user_id)
{
return Jf::$Rbac->enforce($permission, $user_id);
}
public function reset($ensure = false)
{
return Jf::$Rbac->reset($ensure);
}
public function tablePrefix()
{
return Jf::$Rbac->tablePrefix();
}
}
/** @} */ // End group phprbac */

View File

@@ -0,0 +1,207 @@
<?php
require_once __DIR__."/rbac.php";
class Jf
{
/**
* @var RbacManager
*/
public static $Rbac;
public static $Db = null;
public static $TABLE_PREFIX;
private static $groupConcatLimitChanged = false;
public static function setTablePrefix($tablePrefix)
{
self::$TABLE_PREFIX = $tablePrefix;
}
public static function tablePrefix()
{
return self::$TABLE_PREFIX;
}
/**
* The Jf::sql function. The behavior of this function is as follows:
*
* * On queries with no parameters, it should use query function and fetch all results (no prepared statement)
* * On queries with parameters, parameters are provided as question marks (?) and then additional function arguments will be
* bound to question marks.
* * On SELECT, it will return 2D array of results or NULL if no result.
* * On DELETE, UPDATE it returns affected rows
* * On INSERT, if auto-increment is available last insert id, otherwise affected rows
*
* @todo currently sqlite always returns sequence number for lastInsertId, so there's no way of knowing if insert worked instead of execute result. all instances of ==1 replaced with >=1 to check for insert
*
* @param string $Query
* @throws Exception
* @return array|integer|null
*/
static function sql($Query)
{
$args = func_get_args ();
if (get_class ( self::$Db ) == "PDO")
return call_user_func_array ( "self::sqlPdo", $args );
else
if (get_class ( self::$Db ) == "mysqli")
return call_user_func_array ( "self::sqlMysqli", $args );
else
throw new Exception ( "Unknown database interface type." );
}
static function sqlPdo($Query)
{
$debug_backtrace = debug_backtrace();
if((isset($debug_backtrace[3])) && ($debug_backtrace[3]['function'] == 'pathId')) {
if (!self::$groupConcatLimitChanged) {
$success = self::$Db->query ("SET SESSION group_concat_max_len = 1000000");
if ($success) {
self::$groupConcatLimitChanged = true;
}
}
}
$args = func_get_args ();
if (count ( $args ) == 1)
{
$result = self::$Db->query ( $Query );
if ($result===false)
return null;
$res=$result->fetchAll ( PDO::FETCH_ASSOC );
if ($res===array())
return null;
return $res;
}
else
{
if (! $stmt = self::$Db->prepare ( $Query ))
{
return false;
}
array_shift ( $args ); // remove $Query from args
$i = 0;
foreach ( $args as &$v )
$stmt->bindValue ( ++ $i, $v );
$success=$stmt->execute ();
$type = substr ( trim ( strtoupper ( $Query ) ), 0, 6 );
if ($type == "INSERT")
{
if (!$success)
return null;
$res = self::$Db->lastInsertId ();
if ($res == 0)
return $stmt->rowCount ();
return $res;
}
elseif ($type == "DELETE" or $type == "UPDATE" or $type == "REPLACE")
return $stmt->rowCount();
elseif ($type == "SELECT")
{
$res=$stmt->fetchAll ( PDO::FETCH_ASSOC );
if ($res===array())
return null;
else
return $res;
}
}
}
static function sqlMysqli( $Query)
{
$debug_backtrace = debug_backtrace();
if((isset($debug_backtrace[3])) && ($debug_backtrace[3]['function'] == 'pathId')) {
if (!self::$groupConcatLimitChanged) {
$success = self::$Db->query ("SET SESSION group_concat_max_len = 1000000");
if ($success) {
self::$groupConcatLimitChanged = true;
}
}
}
$args = func_get_args ();
if (count ( $args ) == 1)
{
$result = self::$Db->query ( $Query );
if ($result===true)
return true;
if ($result && $result->num_rows)
{
$out = array ();
while ( null != ($r = $result->fetch_array ( MYSQLI_ASSOC )) )
$out [] = $r;
return $out;
}
return null;
}
else
{
if (! $preparedStatement = self::$Db->prepare ( $Query ))
trigger_error ( "Unable to prepare statement: {$Query}, reason: ".self::$Db->error );
array_shift ( $args ); // remove $Query from args
$a = array ();
foreach ( $args as $k => &$v )
$a [$k] = &$v;
$types = str_repeat ( "s", count ( $args ) ); // all params are
// strings, works well on
// MySQL
// and SQLite
array_unshift ( $a, $types );
call_user_func_array ( array ($preparedStatement, 'bind_param' ), $a );
$preparedStatement->execute ();
$type = substr ( trim ( strtoupper ( $Query ) ), 0, 6 );
if ($type == "INSERT")
{
$res = self::$Db->insert_id;
if ($res == 0)
return self::$Db->affected_rows;
return $res;
}
elseif ($type == "DELETE" or $type == "UPDATE" or $type == "REPLAC")
return self::$Db->affected_rows;
elseif ($type == "SELECT")
{
// fetching all results in a 2D array
$metadata = $preparedStatement->result_metadata ();
$out = array ();
$fields = array ();
if (! $metadata)
return null;
while ( null != ($field = $metadata->fetch_field ()) )
$fields [] = &$out [$field->name];
call_user_func_array ( array ($preparedStatement, "bind_result" ), $fields );
$output = array ();
$count = 0;
while ( $preparedStatement->fetch () )
{
foreach ( $out as $k => $v )
$output [$count] [$k] = $v;
$count ++;
}
$preparedStatement->free_result ();
return ($count == 0) ? null : $output;
}
else
return null;
}
}
static function time()
{
return time();
}
}
Jf::setTablePrefix($tablePrefix);
Jf::$Rbac=new RbacManager();
require_once __DIR__."/../setup.php";

View File

@@ -0,0 +1,397 @@
<?php
interface NestedSetInterface
{
public function insertChild($PID=0);
public function insertSibling($ID=0);
function deleteSubtree($ID);
function delete($ID);
//function Move($ID,$NewPID);
//function Copy($ID,$NewPID);
function fullTree();
function children($ID);
function descendants($ID,$AbsoluteDepths=false);
function leaves($PID=null);
function path($ID);
function depth($ID);
function parentNode($ID);
function sibling($ID,$SiblingDistance=1);
}
/**
* BaseNestedSet Class
* This class provides a means to implement Hierarchical data in flat SQL tables.
* Queries extracted from http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
*
* Tested and working properly
*
* Usage:
* have a table with at least 3 INT fields for ID,Left and Right.
* Create a new instance of this class and pass the name of table and name of the 3 fields above
*/
//FIXME: many of these operations should be done in a transaction
class BaseNestedSet implements NestedSetInterface
{
function __construct($Table,$IDField="ID",$LeftField="Left",$RightField="Right")
{
$this->assign($Table,$IDField,$LeftField,$RightField);
}
private $Table;
private $Left,$Right;
private $ID;
protected function id()
{
return $this->ID;
}
protected function table()
{
return $this->Table;
}
protected function left()
{
return $this->Left;
}
protected function right()
{
return $this->Right;
}
/**
* Assigns fields of the table
*
* @param String $Table
* @param String $ID
* @param String $Left
* @param String $Right
*/
protected function assign($Table,$ID,$Left,$Right)
{
$this->Table=$Table;
$this->ID=$ID;
$this->Left=$Left;
$this->Right=$Right;
}
/**
* Returns number of descendants
*
* @param Integer $ID
* @return Integer Count
*/
function descendantCount($ID)
{
$Res=Jf::sql("SELECT ({$this->right()}-{$this->left()}-1)/2 AS `Count` FROM
{$this->table()} WHERE {$this->id()}=?",$ID);
return sprintf("%d",$Res[0]["Count"])*1;
}
/**
* Returns the depth of a node in the tree
* Note: this uses path
* @param Integer $ID
* @return Integer Depth from zero upwards
* @seealso path
*/
function depth($ID)
{
return count($this->path($ID))-1;
}
/**
* Returns a sibling of the current node
* Note: You can't find siblings of roots
* Note: this is a heavy function on nested sets, uses both children (which is quite heavy) and path
* @param Integer $ID
* @param Integer $SiblingDistance from current node (negative or positive)
* @return Array Node on success, null on failure
*/
function sibling($ID,$SiblingDistance=1)
{
$Parent=$this->parentNode($ID);
$Siblings=$this->children($Parent[$this->id()]);
if (!$Siblings) return null;
foreach ($Siblings as &$Sibling)
{
if ($Sibling[$this->id()]==$ID) break;
$n++;
}
return $Siblings[$n+$SiblingDistance];
}
/**
* Returns the parent of a node
* Note: this uses path
* @param Integer $ID
* @return Array parentNode (null on failure)
* @seealso path
*/
function parentNode($ID)
{
$Path=$this->path($ID);
if (count($Path)<2) return null;
else return $Path[count($Path)-2];
}
/**
* Deletes a node and shifts the children up
*
* @param Integer $ID
*/
function delete($ID)
{
$Info=Jf::sql("SELECT {$this->left()} AS `Left`,{$this->right()} AS `Right`
FROM {$this->table()}
WHERE {$this->id()} = ?;
",$ID);
$Info=$Info[0];
$count=Jf::sql("DELETE FROM {$this->table()} WHERE {$this->left()} = ?",$Info["Left"]);
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} - 1, `".
$this->left."` = {$this->left()} - 1 WHERE {$this->left()} BETWEEN ? AND ?",$Info["Left"],$Info["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} - 2 WHERE `".
$this->Right."` > ?",$Info["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->left()} = {$this->left()} - 2 WHERE `".
$this->left."` > ?",$Info["Right"]);
return $count;
}
/**
* Deletes a node and all its descendants
*
* @param Integer $ID
*/
function deleteSubtree($ID)
{
$Info=Jf::sql("SELECT {$this->left()} AS `Left`,{$this->right()} AS `Right` ,{$this->right()}-{$this->left()}+ 1 AS Width
FROM {$this->table()}
WHERE {$this->id()} = ?;
",$ID);
$Info=$Info[0];
$count=Jf::sql("
DELETE FROM {$this->table()} WHERE {$this->left()} BETWEEN ? AND ?
",$Info["Left"],$Info["Right"]);
Jf::sql("
UPDATE {$this->table()} SET {$this->right()} = {$this->right()} - ? WHERE {$this->right()} > ?
",$Info["Width"],$Info["Right"]);
Jf::sql("
UPDATE {$this->table()} SET {$this->left()} = {$this->left()} - ? WHERE {$this->left()} > ?
",$Info["Width"],$Info["Right"]);
return $count;
}
/**
* Returns all descendants of a node
*
* @param Integer $ID
* @param Boolean $AbsoluteDepths to return Depth of sub-tree from zero or absolutely from the whole tree
* @return Rowset including Depth field
* @seealso children
*/
function descendants($ID,$AbsoluteDepths=false)
{
if (!$AbsoluteDepths)
$DepthConcat="- (sub_tree.depth )";
$Res=Jf::sql("
SELECT node.*, (COUNT(parent.{$this->id()})-1 $DepthConcat ) AS Depth
FROM {$this->table()} AS node,
{$this->table()} AS parent,
{$this->table()} AS sub_parent,
(
SELECT node.{$this->id()}, (COUNT(parent.{$this->id()}) - 1) AS depth
FROM {$this->table()} AS node,
{$this->table()} AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->id()} = ?
GROUP BY node.{$this->id()}
ORDER BY node.{$this->left()}
) AS sub_tree
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->left()} BETWEEN sub_parent.{$this->left()} AND sub_parent.{$this->right()}
AND sub_parent.{$this->id()} = sub_tree.{$this->id()}
GROUP BY node.{$this->id()}
HAVING Depth > 0
ORDER BY node.{$this->left()}",$ID);
return $Res;
}
/**
* Returns immediate children of a node
* Note: this function performs the same as descendants but only returns results with Depth=1
* @param Integer $ID
* @return Rowset not including Depth
* @seealso descendants
*/
function children($ID)
{
$Res=Jf::sql("
SELECT node.*, (COUNT(parent.{$this->id()})-1 - (sub_tree.depth )) AS Depth
FROM {$this->table()} AS node,
{$this->table()} AS parent,
{$this->table()} AS sub_parent,
(
SELECT node.{$this->id()}, (COUNT(parent.{$this->id()}) - 1) AS depth
FROM {$this->table()} AS node,
{$this->table()} AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->id()} = ?
GROUP BY node.{$this->id()}
ORDER BY node.{$this->left()}
) AS sub_tree
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->left()} BETWEEN sub_parent.{$this->left()} AND sub_parent.{$this->right()}
AND sub_parent.{$this->id()} = sub_tree.{$this->id()}
GROUP BY node.{$this->id()}
HAVING Depth = 1
ORDER BY node.{$this->left()};
",$ID);
if ($Res)
foreach ($Res as &$v)
unset($v["Depth"]);
return $Res;
}
/**
* Returns the path to a node, including the node
*
* @param Integer $ID
* @return Rowset nodes in path
*/
function path($ID)
{
$Res=Jf::sql("
SELECT parent.*
FROM {$this->table()} AS node,
".$this->table." AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->id()} = ?
ORDER BY parent.{$this->left()}",$ID);
return $Res;
}
/**
* Finds all leaves of a parent
* Note: if you don' specify $PID, There would be one less AND in the SQL Query
* @param Integer $PID
* @return Rowset Leaves
*/
function leaves($PID=null)
{
if ($PID)
$Res=Jf::sql("SELECT *
FROM {$this->table()}
WHERE {$this->right()} = {$this->left()} + 1
AND {$this->left()} BETWEEN
(SELECT {$this->left()} FROM {$this->table()} WHERE {$this->id()}=?)
AND
(SELECT {$this->right()} FROM {$this->table()} WHERE {$this->id()}=?)",$PID,$PID);
else
$Res=Jf::sql("SELECT *
FROM {$this->table()}
WHERE {$this->right()} = {$this->left()} + 1");
return $Res;
}
/**
* Adds a sibling after a node
*
* @param Integer $ID
* @return Integer SiblingID
*/
function insertSibling($ID=0)
{
// $this->DB->AutoQuery("LOCK TABLE {$this->table()} WRITE;");
//Find the Sibling
$Sibl=Jf::sql("SELECT {$this->right()} AS `Right`".
" FROM {$this->table()} WHERE {$this->id()} = ?",$ID);
$Sibl=$Sibl[0];
if ($Sibl==null)
{
$Sibl["Right"]=0;
}
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} + 2 WHERE {$this->right()} > ?",$Sibl["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->left()} = {$this->left()} + 2 WHERE {$this->left()} > ?",$Sibl["Right"]);
$Res= Jf::sql("INSERT INTO {$this->table()} ({$this->left()},{$this->right()}) ".
"VALUES(?,?)",$Sibl["Right"]+1,$Sibl["Right"]+2);
// $this->DB->AutoQuery("UNLOCK TABLES");
return $Res;
}
/**
* Adds a child to the beginning of a node's children
*
* @param Integer $PID
* @return Integer ChildID
*/
function insertChild($PID=0)
{
//Find the Sibling
$Sibl=Jf::sql("SELECT {$this->left()} AS `Left`".
" FROM {$this->table()} WHERE {$this->id()} = ?",$PID);
$Sibl=$Sibl[0];
if ($Sibl==null)
{
$Sibl["Left"]=0;
}
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} + 2 WHERE {$this->right()} > ?",$Sibl["Left"]);
Jf::sql("UPDATE {$this->table()} SET {$this->left()} = {$this->left()} + 2 WHERE {$this->left()} > ?",$Sibl["Left"]);
$Res=Jf::sql("INSERT INTO {$this->table()} ({$this->left()},{$this->right()}) ".
"VALUES(?,?)",$Sibl["Left"]+1,$Sibl["Left"]+2);
return $Res;
}
/**
* Retrives the full tree including Depth field.
*
* @return 2DArray Rowset
*/
function fullTree()
{
$Res=Jf::sql("SELECT node.*, (COUNT(parent.{$this->id()}) - 1) AS Depth
FROM {$this->table()} AS node,
{$this->table()} AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
GROUP BY node.{$this->id()}
ORDER BY node.{$this->left()}");
return $Res;
}
/**
* This function converts a 2D array with Depth fields into a multidimensional tree in an associative array
*
* @param Array $Result
* @return Array Tree
*/
#FIXME: think how to implement this!
/**
function Result2Tree($Result)
{
$out=array();
$stack=array();
$cur=&$out;
foreach($Result as $R)
{
if ($cur[$LastKey]['Depth']==$R['Depth'])
{
echo "adding 0 ".$R['Title'].BR;
$cur[$R[$this->id()]]=$R;
$LastKey=$R[$this->id()];
}
elseif ($cur[$LastKey]['Depth']<$R['Depth'])
{
echo "adding 1 ".$R['Title'].BR;
array_push($stack,$cur);
$cur=&$cur[$LastKey];
$cur[$R[$this->id()]]=$R;
$LastKey=$R[$this->id()];
}
elseif ($cur[$LastKey]['Depth']>$R['Depth'])
{
echo "adding 2 ".$R['Title'].BR;
$cur=array_pop($stack);
$cur[$R[$this->id()]]=$R;
$LastKey=$R[$this->id()];
}
}
return $out;
}
/**/
}
?>

View File

@@ -0,0 +1,494 @@
<?php
interface ExtendedNestedSet extends NestedSetInterface
{
//All functions with ConditionString, accept other parameters in variable numbers
function getID($ConditionString);
function insertChildData($FieldValueArray=array(),$ConditionString=null);
function insertSiblingData($FieldValueArray=array(),$ConditionString=null);
function deleteSubtreeConditional($ConditionString);
function deleteConditional($ConditionString);
function childrenConditional($ConditionString);
function descendantsConditional($AbsoluteDepths=false,$ConditionString);
function leavesConditional($ConditionString=null);
function pathConditional($ConditionString);
function depthConditional($ConditionString);
function parentNodeConditional($ConditionString);
function siblingConditional($SiblingDistance=1,$ConditionString);
/**/
}
/**
* FullNestedSet Class
* This class provides a means to implement Hierarchical data in flat SQL tables.
* Queries extracted from http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
* Tested and working properly.
*
* Usage:
* have a table with at least 3 INT fields for ID,Left and Right.
* Create a new instance of this class and pass the name of table and name of the 3 fields above
*/
class FullNestedSet extends BaseNestedSet implements ExtendedNestedSet
{
/**
public $AutoRipRightLeft=true;
private function RipRightLeft(&$ResultSet)
{
if ($this->AutoRipRightLeft && $ResultSet)
foreach ($ResultSet as &$v)
{
if (isset($v[$this->Left]))
unset($v[$this->Left]);
if (isset($v[$this->Right]))
unset($v[$this->Right]);
}
}
**/
protected function lock()
{
Jf::sql("LOCK TABLE {$this->table()} WRITE");
}
protected function unlock()
{
Jf::sql("UNLOCK TABLES");
}
/**
* Returns the ID of a node based on a SQL conditional string
* It accepts other params in the PreparedStatements format
* @param string $Condition the SQL condition, such as Title=?
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Integer ID
*/
function getID($ConditionString,$Rest=null)
{
$args=func_get_args();
array_shift($args);
$Query="SELECT {$this->id()} AS ID FROM {$this->table()} WHERE $ConditionString LIMIT 1";
array_unshift($args,$Query);
$Res=call_user_func_array(("Jf::sql"),$args);
if ($Res)
return $Res[0]["ID"];
else
return null;
}
/**
* Returns the record of a node based on a SQL conditional string
* It accepts other params in the PreparedStatements format
* @param String $Condition
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Array Record
*/
function getRecord($ConditionString,$Rest=null)
{
$args=func_get_args();
array_shift($args);
$Query="SELECT * FROM {$this->table()} WHERE $ConditionString";
array_unshift($args,$Query);
$Res=call_user_func_array(("Jf::sql"),$args);
if ($Res)
return $Res[0];
else
return null;
}
/**
* Returns the depth of a node in the tree
* Note: this uses path
* @param String $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Integer Depth from zero upwards
* @seealso path
*/
function depthConditional($ConditionString,$Rest=null)
{
$Arguments=func_get_args();
$Path=call_user_func_array(array($this,"pathConditional"),$Arguments);
return count($Path)-1;
}
/**
* Returns a sibling of the current node
* Note: You can't find siblings of roots
* Note: this is a heavy function on nested sets, uses both children (which is quite heavy) and path
* @param Integer $SiblingDistance from current node (negative or positive)
* @param string $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Array Node on success, null on failure
*/
function siblingConditional($SiblingDistance=1,$ConditionString,$Rest=null)
{
$Arguments=func_get_args();
$ConditionString=$ConditionString; //prevent warning
array_shift($Arguments); //Rid $SiblingDistance
$Parent=call_user_func_array(array($this,"parentNodeConditional"),$Arguments);
$Siblings=$this->children($Parent[$this->id()]);
if (!$Siblings) return null;
$ID=call_user_func_array(array($this,"getID"),$Arguments);
foreach ($Siblings as &$Sibling)
{
if ($Sibling[$this->id()]==$ID) break;
$n++;
}
return $Siblings[$n+$SiblingDistance];
}
/**
* Returns the parent of a node
* Note: this uses path
* @param string $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Array parentNode (null on failure)
* @seealso path
*/
function parentNodeConditional($ConditionString,$Rest=null)
{
$Arguments=func_get_args();
$Path=call_user_func_array(array($this,"pathConditional"),$Arguments);
if (count($Path)<2) return null;
else return $Path[count($Path)-2];
}
/**
* Deletes a node and shifts the children up
* Note: use a condition to support only 1 row, LIMIT 1 used.
* @param String $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return boolean
*/
function deleteConditional($ConditionString,$Rest=null)
{
$this->lock();
$Arguments=func_get_args();
array_shift($Arguments);
$Query="SELECT {$this->left()} AS `Left`,{$this->right()} AS `Right`
FROM {$this->table()}
WHERE $ConditionString LIMIT 1";
array_unshift($Arguments,$Query);
$Info=call_user_func_array("Jf::sql",$Arguments);
if (!$Info)
{
$this->unlock();
return false;
}
$Info=$Info[0];
$count=Jf::sql("DELETE FROM {$this->table()} WHERE {$this->left()} = ?",$Info["Left"]);
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} - 1, {$this->left()} = {$this->left()} - 1 WHERE {$this->left()} BETWEEN ? AND ?",$Info["Left"],$Info["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} - 2 WHERE {$this->right()} > ?",$Info["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->left()} = {$this->left()} - 2 WHERE {$this->left()} > ?",$Info["Right"]);
$this->unlock();
return $count==1;
}
/**
* Deletes a node and all its descendants
*
* @param String $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
*/
function deleteSubtreeConditional($ConditionString,$Rest=null)
{
$this->lock();
$Arguments=func_get_args();
array_shift($Arguments);
$Query="SELECT {$this->left()} AS `Left`,{$this->right()} AS `Right` ,{$this->right()}-{$this->left()}+ 1 AS Width
FROM {$this->table()}
WHERE $ConditionString";
array_unshift($Arguments,$Query);
$Info=call_user_func_array("Jf::sql",$Arguments);
$Info=$Info[0];
$count=Jf::sql("
DELETE FROM {$this->table()} WHERE {$this->left()} BETWEEN ? AND ?
",$Info["Left"],$Info["Right"]);
Jf::sql("
UPDATE {$this->table()} SET {$this->right()} = {$this->right()} - ? WHERE {$this->right()} > ?
",$Info["Width"],$Info["Right"]);
Jf::sql("
UPDATE {$this->table()} SET {$this->left()} = {$this->left()} - ? WHERE {$this->left()} > ?
",$Info["Width"],$Info["Right"]);
$this->unlock();
return $count>=1;
}
/**
* Returns all descendants of a node
* Note: use only a sinlge condition here
* @param boolean $AbsoluteDepths to return Depth of sub-tree from zero or absolutely from the whole tree
* @param string $Condition
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Rowset including Depth field
* @seealso children
*/
function descendantsConditional($AbsoluteDepths=false,$ConditionString,$Rest=null)
{
if (!$AbsoluteDepths)
$DepthConcat="- (sub_tree.innerDepth )";
$Arguments=func_get_args();
array_shift($Arguments);
array_shift($Arguments); //second argument, $AbsoluteDepths
$Query="
SELECT node.*, (COUNT(parent.{$this->id()})-1 $DepthConcat) AS Depth
FROM {$this->table()} AS node,
{$this->table()} AS parent,
{$this->table()} AS sub_parent,
(
SELECT node.{$this->id()}, (COUNT(parent.{$this->id()}) - 1) AS innerDepth
FROM {$this->table()} AS node,
{$this->table()} AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND (node.$ConditionString)
GROUP BY node.{$this->id()}
ORDER BY node.{$this->left()}
) AS sub_tree
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->left()} BETWEEN sub_parent.{$this->left()} AND sub_parent.{$this->right()}
AND sub_parent.{$this->id()} = sub_tree.{$this->id()}
GROUP BY node.{$this->id()}
HAVING Depth > 0
ORDER BY node.{$this->left()}";
array_unshift($Arguments,$Query);
$Res=call_user_func_array("Jf::sql",$Arguments);
return $Res;
}
/**
* Returns immediate children of a node
* Note: this function performs the same as descendants but only returns results with Depth=1
* Note: use only a sinlge condition here
* @param string $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Rowset not including Depth
* @seealso descendants
*/
function childrenConditional($ConditionString,$Rest=null)
{
$Arguments=func_get_args();
array_shift($Arguments);
$Query="
SELECT node.*, (COUNT(parent.{$this->id()})-1 - (sub_tree.innerDepth )) AS Depth
FROM {$this->table()} AS node,
{$this->table()} AS parent,
{$this->table()} AS sub_parent,
(
SELECT node.{$this->id()}, (COUNT(parent.{$this->id()}) - 1) AS innerDepth
FROM {$this->table()} AS node,
{$this->table()} AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND (node.$ConditionString)
GROUP BY node.{$this->id()}
ORDER BY node.{$this->left()}
) AS sub_tree
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND node.{$this->left()} BETWEEN sub_parent.{$this->left()} AND sub_parent.{$this->right()}
AND sub_parent.{$this->id()} = sub_tree.{$this->id()}
GROUP BY node.{$this->id()}
HAVING Depth = 1
ORDER BY node.{$this->left()}";
array_unshift($Arguments,$Query);
$Res=call_user_func_array("Jf::sql",$Arguments);
if ($Res)
foreach ($Res as &$v)
unset($v["Depth"]);
return $Res;
}
/**
* Returns the path to a node, including the node
* Note: use a single condition, or supply "node." before condition fields.
* @param string $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Rowset nodes in path
*/
function pathConditional($ConditionString,$Rest=null)
{
$Arguments=func_get_args();
array_shift($Arguments);
$Query="
SELECT parent.*
FROM {$this->table()} AS node,
{$this->table()} AS parent
WHERE node.{$this->left()} BETWEEN parent.{$this->left()} AND parent.{$this->right()}
AND ( node.$ConditionString )
ORDER BY parent.{$this->left()}";
array_unshift($Arguments,$Query);
$Res=call_user_func_array("Jf::sql",$Arguments);
return $Res;
}
/**
* Finds all leaves of a parent
* Note: if you don' specify $PID, There would be one less AND in the SQL Query
* @param String $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Rowset Leaves
*/
function leavesConditional($ConditionString=null,$Rest=null)
{
if ($ConditionString)
{
$Arguments=func_get_args();
array_shift($Arguments);
if ($ConditionString) $ConditionString="WHERE $ConditionString";
$Query="SELECT *
FROM {$this->table()}
WHERE {$this->right()} = {$this->left()} + 1
AND {$this->left()} BETWEEN
(SELECT {$this->left()} FROM {$this->table()} $ConditionString)
AND
(SELECT {$this->right()} FROM {$this->table()} $ConditionString)";
$Arguments=array_merge($Arguments,$Arguments);
array_unshift($Arguments,$Query);
$Res=call_user_func_array("Jf::sql",$Arguments);
}
else
$Res=Jf::sql("SELECT *
FROM {$this->table()}
WHERE {$this->right()} = {$this->left()} + 1");
return $Res;
}
/**
* Adds a sibling after a node
*
* @param array $FieldValueArray Pairs of Key/Value as Field/Value in the table
* @param string $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string
* @return Integer SiblingID
*/
function insertSiblingData($FieldValueArray=array(),$ConditionString=null,$Rest=null)
{
$this->lock();
//Find the Sibling
$Arguments=func_get_args();
array_shift($Arguments); //first argument, the array
array_shift($Arguments);
if ($ConditionString) $ConditionString="WHERE $ConditionString";
$Query="SELECT {$this->right()} AS `Right`".
" FROM {$this->table()} $ConditionString";
array_unshift($Arguments,$Query);
$Sibl=call_user_func_array("Jf::sql",$Arguments);
$Sibl=$Sibl[0];
if ($Sibl==null)
{
$Sibl["Left"]=$Sibl["Right"]=0;
}
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} + 2 WHERE {$this->right()} > ?",$Sibl["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->left()} = {$this->left()} + 2 WHERE {$this->left()} > ?",$Sibl["Right"]);
$FieldsString=$ValuesString="";
$Values=array();
if ($FieldValueArray)
foreach($FieldValueArray as $k=>$v)
{
$FieldsString.=",";
$FieldsString.="`".$k."`";
$ValuesString.=",?";
$Values[]=$v;
}
$Query= "INSERT INTO {$this->table()} ({$this->left()},{$this->right()} $FieldsString) ".
"VALUES(?,? $ValuesString)";
array_unshift($Values,$Sibl["Right"]+2);
array_unshift($Values,$Sibl["Right"]+1);
array_unshift($Values,$Query);
$Res=call_user_func_array("Jf::sql",$Values);
$this->unlock();
return $Res;
}
/**
* Adds a child to the beginning of a node's children
*
* @param Array $FieldValueArray key-paired field-values to insert
* @param string $ConditionString of the parent node
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Integer ChildID
*/
function insertChildData($FieldValueArray=array(),$ConditionString=null,$Rest=null)
{
$this->lock();
//Find the Sibling
$Arguments=func_get_args();
array_shift($Arguments); //first argument, the array
array_shift($Arguments);
if ($ConditionString) $ConditionString="WHERE $ConditionString";
$Query="SELECT {$this->right()} AS `Right`, {$this->left()} AS `Left`".
" FROM {$this->table()} $ConditionString";
array_unshift($Arguments,$Query);
$Parent=call_user_func_array("Jf::sql",$Arguments);
$Parent=$Parent[0];
if ($Parent==null)
{
$Parent["Left"]=$Parent["Right"]=0;
}
Jf::sql("UPDATE {$this->table()} SET {$this->right()} = {$this->right()} + 2 WHERE {$this->right()} >= ?",$Parent["Right"]);
Jf::sql("UPDATE {$this->table()} SET {$this->left()} = {$this->left()} + 2 WHERE {$this->left()} > ?",$Parent["Right"]);
$FieldsString=$ValuesString="";
$Values=array();
if ($FieldValueArray)
foreach($FieldValueArray as $k=>$v)
{
$FieldsString.=",";
$FieldsString.="`".$k."`";
$ValuesString.=",?";
$Values[]=$v;
}
$Query= "INSERT INTO {$this->table()} ({$this->left()},{$this->right()} $FieldsString) ".
"VALUES(?,? $ValuesString)";
array_unshift($Values,$Parent["Right"]+1);
array_unshift($Values,$Parent["Right"]);
array_unshift($Values,$Query);
$Res=call_user_func_array("Jf::sql",$Values);
$this->unlock();
return $Res;
}
/**
* Edits a node
*
* @param Array $FieldValueArray Pairs of Key/Value as Field/Value in the table to edit
* @param string $ConditionString
* @param string $Rest optional, rest of variables to fill in placeholders of condition string, one variable for each ? in condition
* @return Integer SiblingID
*/
function editData($FieldValueArray=array(),$ConditionString=null,$Rest=null)
{
//Find the Sibling
$Arguments=func_get_args();
array_shift($Arguments); //first argument, the array
array_shift($Arguments);
if ($ConditionString) $ConditionString="WHERE $ConditionString";
$FieldsString="";
$Values=array();
if ($FieldValueArray)
foreach($FieldValueArray as $k=>$v)
{
if ($FieldsString!="") $FieldsString.=",";
$FieldsString.="`".$k."`=?";
$Values[]=$v;
}
$Query="UPDATE {$this->table()} SET $FieldsString $ConditionString";
array_unshift($Values,$Query);
$Arguments=array_merge($Values,$Arguments);
return call_user_func_array("Jf::sql",$Arguments);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
<?php
#TODO: test on sqlite
if ($adapter=="pdo_mysql")
{
try {
Jf::$Db=new PDO("mysql:host={$host};dbname={$dbname}",$user,$pass);
}
catch (PDOException $e)
{
if ($e->getCode()==1049) //database not found
installPdoMysql($host,$user,$pass,$dbname);
else
throw $e;
}
}
elseif ($adapter=="pdo_sqlite")
{
if (!file_exists($dbname))
installPdoSqlite($host,$user,$pass,$dbname);
else
Jf::$Db=new PDO("sqlite:{$dbname}",$user,$pass);
// Jf::$Db=new PDO("sqlite::memory:",$user,$pass);
}
else # default to mysqli
{
@Jf::$Db=new mysqli($host,$user,$pass,$dbname);
if(jf::$Db->connect_errno==1049)
installMysqli($host,$user,$pass,$dbname);
}
function getSqls($dbms)
{
$sql=file_get_contents(dirname(dirname(dirname(__DIR__))) . "/database/{$dbms}.sql");
$sql=str_replace("PREFIX_",Jf::tablePrefix(),$sql);
return explode(";",$sql);
}
function installPdoMysql($host,$user,$pass,$dbname)
{
$sqls=getSqls("mysql");
$db=new PDO("mysql:host={$host};",$user,$pass);
$db->query("CREATE DATABASE {$dbname}");
$db->query("USE {$dbname}");
if (is_array($sqls))
foreach ($sqls as $query)
$db->query($query);
Jf::$Db=new PDO("mysql:host={$host};dbname={$dbname}",$user,$pass);
Jf::$Rbac->reset(true);
}
function installPdoSqlite($host,$user,$pass,$dbname)
{
Jf::$Db=new PDO("sqlite:{$dbname}",$user,$pass);
$sqls=getSqls("sqlite");
if (is_array($sqls))
foreach ($sqls as $query)
Jf::$Db->query($query);
Jf::$Rbac->reset(true);
}
function installMysqli($host,$user,$pass,$dbname)
{
$sqls=getSqls("mysql");
$db=new mysqli($host,$user,$pass);
$db->query("CREATE DATABASE {$dbname}");
$db->select_db($dbname);
if (is_array($sqls))
foreach ($sqls as $query)
$db->query($query);
Jf::$Db=new mysqli($host,$user,$pass,$dbname);
Jf::$Rbac->reset(true);
}

34
vendor/owasp/phprbac/composer.json vendored Normal file
View File

@@ -0,0 +1,34 @@
{
"name" : "owasp/phprbac",
"type" : "library",
"description" : "PHP-RBAC is the de-facto authorization library for PHP. It provides developers with NIST Level 2 Standard Role Based Access Control and more, in the fastest implementation yet.",
"keywords" : [
"rbac",
"owasp",
"security"
],
"homepage" : "http://phprbac.net/",
"license" : "CC-BY-SA-3.0",
"authors" : [{
"name" : "AbiusX",
"email" : "me@abiusx.com",
"homepage" : "http://abiusx.com/",
"role" : "Lead Developer"
}, {
"name" : "Jesse Burns",
"email" : "jesse.burns@alliancecms.com",
"homepage" : "http://www.jbwebware.com",
"role" : "Developer"
}
],
"autoload" : {
"psr-0" : {
"PhpRbac" : "PhpRbac/src"
}
},
"repositories" : [{
"type" : "vcs",
"url" : "https://github.com/OWASP/rbac.git"
}
]
}