summaryrefslogblamecommitdiffstats
path: root/app/class/table.class.php
blob: 0edff9d1c6f770eb6706982e08fbea1f2afb9c6d (plain) (tree)









































































































































































                                                                                                                         






































                                                                         


  
<?php

/*
 * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * For more information, please refer to UNLICENSE
 */

require_once "class/database.class.php";
require_once "class/databasekeyexception.class.php";

/*
 * This class provides functionality for retrieving data from and updating
 * data in a database table.
 */
abstract class table
{
    /*
     * This is an array acting as a dictionary, mapping a table name (key)
     * into another array acting as a list (value) of the fields in that
     * table.  Classes that extend this class, should append a key=>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);
    }

    /*
     * 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;
    }
}

?>