summaryrefslogblamecommitdiffstats
path: root/app/class/table.class.php
blob: 52a3e7d5fe8f8045ee45cc117403770e47b12e63 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15














                                                                         















                                                                          

                                                                     


                                                                        


                                                     






                                                                        
                                                   


                                                 
                                     
 
                                 
                                                                     


                                                
                                       
                                                                               
                                              









                                             








                                                                     








                                                                            
                                                         


                                                    
                                           






                                            

                                                                                 




                                                                               

                                                                                                                        






                               

                                                         



                                                    
                                           







                                            
                                               
                                           
                                                                        






                                                                                                   
                                            

                 

                                                                             





                                                                           
                                                



                                   
                                                              
 
                                           


                                                
                                       
                                                                             
                                    



                                                                                                
                                

                                                                                              
                                
     



                                                                 
                                             






                                                                     
                                                          

                                         
                                       





                                          
                                                       
     
                                     
                                                                         
                                       





                                                     
                                                 
     

                                                 

                     














                                                                                             


  
<?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";

/*
 * 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();

    /*
     * Instanciate an object representing an existing database entity
     * 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)
    {
        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, an exception is thrown.
     */
    private function loadObj(string $guid) : void
    {
        $guid = database::esc($guid);

        if (!self::isGUID($guid))
            throw new Exception("GUID " . $guid . " does not exist");

        foreach ($this->fields as $tbl => $flds)
        {
            $tbl = database::esc($tbl);
            $query = "SELECT * FROM " . $tbl . " WHERE guid = '" . $guid . "'";
            $res = database::query($query)[0];

            foreach ($flds as $fld)
            {
                if (isset($res[$fld]))
                    $this->$fld = $res[$fld];
            }
        }
    }

    /*
     * 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
     * $fields array to construct SQL queries.
     */
    public function saveObj() : void
    {
        /* update existing object */
        if (isset($this->guid))
        {
            $this->updated = self::getCurrentTimestamp();

            foreach ($this->fields as $tbl => $flds)
            {
                $tbl = database::esc($tbl);
                $udstr = "";

                foreach ($flds as $fld)
                {
                    if (!isset($this->$fld))
                        continue;

                    $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 = '" . database::esc($this->guid) . "'";
                    database::query($query);
                }
            }
        }

        /* create new object */
        else
        {
            $this->guid = self::getNewGUID();
            $this->created = self::getCurrentTimestamp();
            $this->updated = $this->created;

            foreach ($this->fields as $tbl => $flds)
            {
                $tbl = database::esc($tbl);
                $fldstr = "";
                $valstr = "";

                foreach ($flds as $fld)
                {
                    if (!isset($this->$fld))
                        continue;

                    $fld = database::esc($fld);
                    $fldstr .= $fld . ", ";
                    $valstr .= "'" . database::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 . ")";
                    database::query($query);
                }
            }

            $this->refreshObj(); // fetch default, unset values from database
        }
    }

    /*
     * 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 an exception.
     */
    public function delObj() : void
    {
        if (!isset($this->guid))
            throw new Exception("GUID (null) does not exist");

        $guid = database::esc($this->guid);

        foreach ($this->fields as $tbl => $flds)
        {
            $tbl = database::esc($tbl);
            $query = "DELETE FROM " . $tbl . " WHERE guid = '" . $guid . "'";
            database::query($query);
        }

        /* garbage collection */
        $query = "DELETE FROM members WHERE guid = '" . $guid . "' OR member = '" . $guid . "'";
        database::query($query);

        $query = "DELETE FROM views WHERE guid = '" . $guid . "' OR viewer = '" . $guid . "'";
        database::query($query);
    }

    /*
     * Get a random sha256 blob, returned as a hexadecimal string
     */
    public static function getBlob() : string
    {
        return hash("sha256", openssl_random_pseudo_bytes(64));
    }

    /*
     * Get current timestamp as a string for object database purposes
     */
    private static function getCurrentTimestamp() : string
    {
        $query = "SELECT now() AS stamp";
        $res = database::query($query);
        return $res[0]['stamp'];
    }

    /*
     * Check whether the given GUID exists
     */
    private static function isGUID(string $guid) : bool
    {
        $guid = database::esc($guid);
        $query = "SELECT guid FROM objects WHERE guid = '" . $guid . "'";
        $res = database::query($query);
        return count($res) > 0;
    }

    /*
     * Get a new, unique GUID for a new system object
     */
    private static function getNewGUID() : string
    {
        do $guid = substr(self::getBlob(), 0, 8);
        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 . ".");
        }
    }
}

?>