From a17463ee221da81d394d4571e3e9b0f2e52d965f Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 15 Jan 2017 04:43:33 -0500 Subject: Add table class --- app/class/table.class.php | 173 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 app/class/table.class.php (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php new file mode 100644 index 0000000..62f95d3 --- /dev/null +++ b/app/class/table.class.php @@ -0,0 +1,173 @@ +val to + * this array that represents the table being modeled. This array is + * used by db table IO functions to construct SQL queries. + */ + protected $fields = array(); + + protected $db; + + /* + * Instanciate an object representing an existing database entity + * named by the given GUID. If no such GUID exists, a + * databasekeyexception is thrown. If NULL is passed, no database + * lookups are attempted. This is helpful for assembling new database + * objects. + */ + public function __construct(?string $guid = NULL) + { + $this->db = database::getInstance(); + + if ($guid) + $this->loadObj($guid); + } + + /* + * This function will iterate the $fields array and initialize this + * object's class properties based on the table=>fields mapping. If + * no such GUID exists, a databasekeyexception is thrown. + */ + private function loadObj(string $guid) : void + { + $guid = $this->db->esc($guid); + + if (!$this->isGUID($guid)) + throw new databasekeyexception("GUID " . $guid . " does not exist"); + + foreach ($this->fields as $tbl => $flds) + { + $tbl = $this->db->esc($tbl); + $query = "SELECT * FROM " . $tbl . " WHERE guid = '" . $guid . "'"; + $res = $this->db->query($query)[0]; + + foreach ($flds as $fld) + { + if (isset($res[$fld])) + $this->$fld = $res[$fld]; + } + } + } + + /* + * This function will update this object in the database, or insert new + * data if this object does not yet have a GUID. This function uses the + * $fields array to construct SQL queries. + */ + public function saveObj() : void + { + /* update existing object */ + if (isset($this->guid)) + { + $this->updated = $this->getCurrentTimestamp(); + + foreach ($this->fields as $tbl => $flds) + { + $tbl = $this->db->esc($tbl); + $udstr = ""; + + foreach ($flds as $fld) + { + if (!isset($this->$fld)) + continue; + + $fld = $this->db->esc($fld); + $udstr .= $fld . " = '" . $this->db->esc($this->$fld) . "', "; + } + + if (strlen($udstr) > 0) + { + $udstr = substr($udstr, 0, -2); // remove ", " from the end + $query = "UPDATE " . $tbl . " SET " . $udstr . " WHERE guid = '" . $this->db->esc($this->guid) . "'"; + $this->db->query($query); + } + } + } + + /* create new object */ + else + { + $this->guid = $this->getNewGUID(); + $this->created = $this->getCurrentTimestamp(); + $this->updated = $this->created; + + foreach ($this->fields as $tbl => $flds) + { + $tbl = $this->db->esc($tbl); + $fldstr = ""; + $valstr = ""; + + foreach ($flds as $fld) + { + if (!isset($this->$fld)) + continue; + + $fld = $this->db->esc($fld); + $fldstr .= $fld . ", "; + $valstr .= "'" . $this->db->esc($this->$fld) . "', "; + } + + if (strlen($fldstr) > 0) + { + $fldstr = substr($fldstr, 0, -2); // remove ", " + $valstr = substr($valstr, 0, -2); + $query = "INSERT INTO " . $tbl . " (" . $fldstr . ") VALUES (" . $valstr . ")"; + $this->db->query($query); + } + } + } + } + + /* + * This function will remove this object from the database by deleting + * rows with this object's GUID from tables in $fields. If this object + * does not have a GUID, throw a databasekeyexception. + */ + public function delObj() : void + { + if (!isset($this->guid)) + throw new databasekeyexception("GUID (null) does not exist"); + + $guid = $this->db->esc($this->guid); + + foreach ($this->fields as $tbl => $flds) + { + $tbl = $this->db->esc($tbl); + $query = "DELETE FROM " . $tbl . " WHERE guid = '" . $guid . "'"; + $this->db->query($query); + } + + /* garbage collection */ + $query = "DELETE FROM members WHERE guid = '" . $guid . "' OR member = '" . $guid . "'"; + $this->db->query($query); + + $query = "DELETE FROM views WHERE guid = '" . $guid . "' OR viewer = '" . $guid . "'"; + $this->db->query($query); + } +} + +?> -- cgit v1.2.3 From 66cf5c4d36ed6020c6ee6b7ca99aecd5a8f3bcf4 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Tue, 17 Jan 2017 03:56:28 -0500 Subject: Add helper functions to table class --- app/class/table.class.php | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 62f95d3..0edff9d 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -168,6 +168,45 @@ abstract class table $query = "DELETE FROM views WHERE guid = '" . $guid . "' OR viewer = '" . $guid . "'"; $this->db->query($query); } + + /* + * Get a random sha256 blob, returned as a hexadecimal string + */ + public function getBlob() : string + { + return hash("sha256", openssl_random_pseudo_bytes(64)); + } + + /* + * Get current timestamp as a string for object database purposes + */ + private function getCurrentTimestamp() : string + { + $query = "SELECT now() AS stamp"; + $res = $this->db->query($query); + return $res[0]['stamp']; + } + + /* + * Check whether the given GUID exists + */ + private function isGUID(string $guid) : bool + { + $guid = $this->db->esc($guid); + $query = "SELECT guid FROM objects WHERE guid = '" . $guid . "'"; + $res = $this->db->query($query); + return count($res) > 0; + } + + /* + * Get a new, unique GUID for a new system object + */ + private function getNewGUID() : string + { + do $guid = substr($this->getBlob(), 0, 8); + while ($this->isGUID($guid)); + return $guid; + } } ?> -- cgit v1.2.3 From 9642aeb3b2fa76fd21a4fa0878bc226f6ff013a5 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 5 Feb 2017 00:42:29 -0500 Subject: Remove custom exception 'databasekeyexception' Just use a generic exception in these cases. I don't want to handle these any differently, and just fall back on the main Exception() error page once we get to a UI. --- app/class/table.class.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 0edff9d..be7a375 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -13,7 +13,6 @@ */ require_once "class/database.class.php"; -require_once "class/databasekeyexception.class.php"; /* * This class provides functionality for retrieving data from and updating @@ -34,10 +33,9 @@ abstract class table /* * Instanciate an object representing an existing database entity - * named by the given GUID. If no such GUID exists, a - * databasekeyexception is thrown. If NULL is passed, no database - * lookups are attempted. This is helpful for assembling new database - * objects. + * named by the given GUID. If no such GUID exists, an exception + * is thrown. If NULL is passed, no database lookups are attempted. + * This is helpful for assembling new database objects. */ public function __construct(?string $guid = NULL) { @@ -50,14 +48,14 @@ abstract class table /* * This function will iterate the $fields array and initialize this * object's class properties based on the table=>fields mapping. If - * no such GUID exists, a databasekeyexception is thrown. + * no such GUID exists, an exception is thrown. */ private function loadObj(string $guid) : void { $guid = $this->db->esc($guid); if (!$this->isGUID($guid)) - throw new databasekeyexception("GUID " . $guid . " does not exist"); + throw new Exception("GUID " . $guid . " does not exist"); foreach ($this->fields as $tbl => $flds) { @@ -145,12 +143,12 @@ abstract class table /* * This function will remove this object from the database by deleting * rows with this object's GUID from tables in $fields. If this object - * does not have a GUID, throw a databasekeyexception. + * does not have a GUID, throw an exception. */ public function delObj() : void { if (!isset($this->guid)) - throw new databasekeyexception("GUID (null) does not exist"); + throw new Exception("GUID (null) does not exist"); $guid = $this->db->esc($this->guid); -- cgit v1.2.3 From 476192ca8fa2053af74a7e7f5e4006c83c8d0cad Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Mon, 6 Feb 2017 01:18:10 -0500 Subject: Update table class tree to use static database references --- app/class/table.class.php | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index be7a375..0b9a53c 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -29,8 +29,6 @@ abstract class table */ protected $fields = array(); - protected $db; - /* * Instanciate an object representing an existing database entity * named by the given GUID. If no such GUID exists, an exception @@ -39,8 +37,6 @@ abstract class table */ public function __construct(?string $guid = NULL) { - $this->db = database::getInstance(); - if ($guid) $this->loadObj($guid); } @@ -52,16 +48,16 @@ abstract class table */ private function loadObj(string $guid) : void { - $guid = $this->db->esc($guid); + $guid = database::esc($guid); if (!$this->isGUID($guid)) throw new Exception("GUID " . $guid . " does not exist"); foreach ($this->fields as $tbl => $flds) { - $tbl = $this->db->esc($tbl); + $tbl = database::esc($tbl); $query = "SELECT * FROM " . $tbl . " WHERE guid = '" . $guid . "'"; - $res = $this->db->query($query)[0]; + $res = database::query($query)[0]; foreach ($flds as $fld) { @@ -85,7 +81,7 @@ abstract class table foreach ($this->fields as $tbl => $flds) { - $tbl = $this->db->esc($tbl); + $tbl = database::esc($tbl); $udstr = ""; foreach ($flds as $fld) @@ -93,15 +89,15 @@ abstract class table if (!isset($this->$fld)) continue; - $fld = $this->db->esc($fld); - $udstr .= $fld . " = '" . $this->db->esc($this->$fld) . "', "; + $fld = database::esc($fld); + $udstr .= $fld . " = '" . database::esc($this->$fld) . "', "; } if (strlen($udstr) > 0) { $udstr = substr($udstr, 0, -2); // remove ", " from the end - $query = "UPDATE " . $tbl . " SET " . $udstr . " WHERE guid = '" . $this->db->esc($this->guid) . "'"; - $this->db->query($query); + $query = "UPDATE " . $tbl . " SET " . $udstr . " WHERE guid = '" . database::esc($this->guid) . "'"; + database::query($query); } } } @@ -115,7 +111,7 @@ abstract class table foreach ($this->fields as $tbl => $flds) { - $tbl = $this->db->esc($tbl); + $tbl = database::esc($tbl); $fldstr = ""; $valstr = ""; @@ -124,9 +120,9 @@ abstract class table if (!isset($this->$fld)) continue; - $fld = $this->db->esc($fld); + $fld = database::esc($fld); $fldstr .= $fld . ", "; - $valstr .= "'" . $this->db->esc($this->$fld) . "', "; + $valstr .= "'" . database::esc($this->$fld) . "', "; } if (strlen($fldstr) > 0) @@ -134,7 +130,7 @@ abstract class table $fldstr = substr($fldstr, 0, -2); // remove ", " $valstr = substr($valstr, 0, -2); $query = "INSERT INTO " . $tbl . " (" . $fldstr . ") VALUES (" . $valstr . ")"; - $this->db->query($query); + database::query($query); } } } @@ -150,21 +146,21 @@ abstract class table if (!isset($this->guid)) throw new Exception("GUID (null) does not exist"); - $guid = $this->db->esc($this->guid); + $guid = database::esc($this->guid); foreach ($this->fields as $tbl => $flds) { - $tbl = $this->db->esc($tbl); + $tbl = database::esc($tbl); $query = "DELETE FROM " . $tbl . " WHERE guid = '" . $guid . "'"; - $this->db->query($query); + database::query($query); } /* garbage collection */ $query = "DELETE FROM members WHERE guid = '" . $guid . "' OR member = '" . $guid . "'"; - $this->db->query($query); + database::query($query); $query = "DELETE FROM views WHERE guid = '" . $guid . "' OR viewer = '" . $guid . "'"; - $this->db->query($query); + database::query($query); } /* @@ -181,7 +177,7 @@ abstract class table private function getCurrentTimestamp() : string { $query = "SELECT now() AS stamp"; - $res = $this->db->query($query); + $res = database::query($query); return $res[0]['stamp']; } @@ -190,9 +186,9 @@ abstract class table */ private function isGUID(string $guid) : bool { - $guid = $this->db->esc($guid); + $guid = database::esc($guid); $query = "SELECT guid FROM objects WHERE guid = '" . $guid . "'"; - $res = $this->db->query($query); + $res = database::query($query); return count($res) > 0; } -- cgit v1.2.3 From 861c98387001f99fe0e178d8202d2c3ec40538f0 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Mon, 6 Feb 2017 02:28:20 -0500 Subject: Update function signatures for table class Various function (and their usages) in the table class have been updated to be static class function. --- app/class/table.class.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 0b9a53c..2759176 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -50,7 +50,7 @@ abstract class table { $guid = database::esc($guid); - if (!$this->isGUID($guid)) + if (!self::isGUID($guid)) throw new Exception("GUID " . $guid . " does not exist"); foreach ($this->fields as $tbl => $flds) @@ -77,7 +77,7 @@ abstract class table /* update existing object */ if (isset($this->guid)) { - $this->updated = $this->getCurrentTimestamp(); + $this->updated = self::getCurrentTimestamp(); foreach ($this->fields as $tbl => $flds) { @@ -105,8 +105,8 @@ abstract class table /* create new object */ else { - $this->guid = $this->getNewGUID(); - $this->created = $this->getCurrentTimestamp(); + $this->guid = self::getNewGUID(); + $this->created = self::getCurrentTimestamp(); $this->updated = $this->created; foreach ($this->fields as $tbl => $flds) @@ -166,7 +166,7 @@ abstract class table /* * Get a random sha256 blob, returned as a hexadecimal string */ - public function getBlob() : string + public static function getBlob() : string { return hash("sha256", openssl_random_pseudo_bytes(64)); } @@ -174,7 +174,7 @@ abstract class table /* * Get current timestamp as a string for object database purposes */ - private function getCurrentTimestamp() : string + private static function getCurrentTimestamp() : string { $query = "SELECT now() AS stamp"; $res = database::query($query); @@ -184,7 +184,7 @@ abstract class table /* * Check whether the given GUID exists */ - private function isGUID(string $guid) : bool + private static function isGUID(string $guid) : bool { $guid = database::esc($guid); $query = "SELECT guid FROM objects WHERE guid = '" . $guid . "'"; @@ -195,10 +195,10 @@ abstract class table /* * Get a new, unique GUID for a new system object */ - private function getNewGUID() : string + private static function getNewGUID() : string { - do $guid = substr($this->getBlob(), 0, 8); - while ($this->isGUID($guid)); + do $guid = substr(self::getBlob(), 0, 8); + while (self::isGUID($guid)); return $guid; } } -- cgit v1.2.3 From f8db4aae02465dabaf7907f5e821414eeeea14bf Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Tue, 7 Feb 2017 00:20:03 -0500 Subject: Add function expectType() to table class protected function exceptType added for use by subclasses to assert that the database object loaded is the correct type and to protect against cases like EG: passing the GUID for a group to new user(...); If a problem is detected, throw an exception. --- app/class/table.class.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 2759176..45be8c5 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -201,6 +201,21 @@ abstract class table while (self::isGUID($guid)); return $guid; } + + /* + * Assert that this object is of the expected type in the database. + * Throw an exception if a type mismatch exists. Check will only + * be performed if guid and objtype are set on this object. + */ + protected function expectType(string $objtype) : void + { + if (isset($this->guid) && isset($this->objtype)) + { + if ($this->objtype != $objtype) + throw new Exception("Invalid object allocation. " . $this->guid . " is a " . + $this->objtype . ", not a " . $objtype . "."); + } + } } ?> -- cgit v1.2.3 From 602921ebd65b8a46190bbcf1eb7a83c409f2c926 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Thu, 13 Apr 2017 21:05:56 -0400 Subject: Add table function refreshObj() --- app/class/table.class.php | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 45be8c5..ac21aaf 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -67,6 +67,15 @@ abstract class table } } + /* + * This function uses loadObj to re-initialize this object, if in + * the case it gets modified in another scope. + */ + public function refreshObj() : void + { + $this->loadObj($this->guid); + } + /* * This function will update this object in the database, or insert new * data if this object does not yet have a GUID. This function uses the -- cgit v1.2.3 From e7228676ce51bf69cc974fc0bd8f8135c51fd036 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Thu, 13 Apr 2017 23:23:56 -0400 Subject: Fix bug in table function saveObj() While creating new objects, some default values (defined in the database schema) are missing in the PHP object definition. To address this, now while saving any *new* database objects, all undefined, expected fields are set to the empty string "". --- app/class/table.class.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index ac21aaf..c547e43 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -127,7 +127,10 @@ abstract class table foreach ($flds as $fld) { if (!isset($this->$fld)) + { + $this->$fld = ""; continue; + } $fld = database::esc($fld); $fldstr .= $fld . ", "; -- cgit v1.2.3 From 025a34dbd54a0886d766f386792310e5f6bfe701 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Fri, 14 Apr 2017 21:01:10 -0400 Subject: Revert "Fix bug in table function saveObj()" This reverts commit e7228676ce51bf69cc974fc0bd8f8135c51fd036. --- app/class/table.class.php | 3 --- 1 file changed, 3 deletions(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index c547e43..ac21aaf 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -127,10 +127,7 @@ abstract class table foreach ($flds as $fld) { if (!isset($this->$fld)) - { - $this->$fld = ""; continue; - } $fld = database::esc($fld); $fldstr .= $fld . ", "; -- cgit v1.2.3 From 453a2fc20886fa25b94017c1cccdbd05456a2d60 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Fri, 14 Apr 2017 20:50:24 -0400 Subject: Fix bug in table function saveObj() Added call to refreshObj() to the end of function saveObj() to fetch all default values defined by the database, not set on the object in PHP. --- app/class/table.class.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index ac21aaf..52a3e7d 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -142,6 +142,8 @@ abstract class table database::query($query); } } + + $this->refreshObj(); // fetch default, unset values from database } } -- cgit v1.2.3 From 575d532b06eeae5eac77f231265e8fd7034d4fd7 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Fri, 7 Sep 2018 07:02:18 -0400 Subject: Fix bug in function table->loadObj() If a table query yeilds zero rows, we would still attempt to load the first (index zero) into $this, causing an error to be thrown by PHP. We are now checking the size of the results array first. --- app/class/table.class.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 52a3e7d..28308bb 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -57,7 +57,13 @@ abstract class table { $tbl = database::esc($tbl); $query = "SELECT * FROM " . $tbl . " WHERE guid = '" . $guid . "'"; - $res = database::query($query)[0]; + $res = database::query($query); + + /* no results */ + if (count($res) == 0) + continue; + + $res = $res[0]; foreach ($flds as $fld) { -- cgit v1.2.3 From e90ec83ac5f9327dcf055174002723b48948a679 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Wed, 19 Sep 2018 17:49:34 -0400 Subject: table: Change function visibilities to public These two functions, 'getCurrentTimestamp()' and 'isGUID()' are updated to be public. There is actually no good reason for them to be private; I originally just never antisipated their use outside this class. I need isGUID() in index.php to help with page routing. Neither of these two functions have side effects of any kind nor any unexpected behavior, so there is no harm in going public. --- app/class/table.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 28308bb..5e4c823 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -191,7 +191,7 @@ abstract class table /* * Get current timestamp as a string for object database purposes */ - private static function getCurrentTimestamp() : string + public static function getCurrentTimestamp() : string { $query = "SELECT now() AS stamp"; $res = database::query($query); @@ -201,7 +201,7 @@ abstract class table /* * Check whether the given GUID exists */ - private static function isGUID(string $guid) : bool + public static function isGUID(string $guid) : bool { $guid = database::esc($guid); $query = "SELECT guid FROM objects WHERE guid = '" . $guid . "'"; -- cgit v1.2.3 From 1daec62c0ab6590d3a30464b2f679baea3ca3936 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Thu, 20 Sep 2018 00:09:08 -0400 Subject: table: Fix bug in constructor This particular flaw was dampening (and could popentially be hiding) the effects of other bugs. For instance, in this case, a GUID of "" was invalidly being used to construct an object. This should obviously be considered an error, but since "" evaluates to false, the construction was treated as default (no GUID) construction and succedded. It wasn't until later when missing properties were accessed that random PHP error messages clued me into what was happening. Now, when any sort of explicit value is used to construct an object (not NULL), an object load will be attempted, giving bad input more chances to fail outright and trigger an exception. In addition, the 'no such guid' exception message is updated to place quotes ('') around the GUID string to make it more obvious when "" is used in the future. --- app/class/table.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/class/table.class.php') diff --git a/app/class/table.class.php b/app/class/table.class.php index 5e4c823..618d938 100644 --- a/app/class/table.class.php +++ b/app/class/table.class.php @@ -37,7 +37,7 @@ abstract class table */ public function __construct(?string $guid = NULL) { - if ($guid) + if ($guid !== NULL) $this->loadObj($guid); } @@ -51,7 +51,7 @@ abstract class table $guid = database::esc($guid); if (!self::isGUID($guid)) - throw new Exception("GUID " . $guid . " does not exist"); + throw new Exception("GUID '" . $guid . "' does not exist"); foreach ($this->fields as $tbl => $flds) { -- cgit v1.2.3