403Webshell
Server IP : 37.9.174.138  /  Your IP : 216.73.216.117
Web Server : Apache
System : Linux vps6.backend.sk 6.12.100+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.100-1 (2026-07-30) x86_64
User : ftpuser ( 1001)
PHP Version : 8.4.24
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/html/backend-accounting.sk/app/app/classes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/backend-accounting.sk/app/app/classes/PDODatabase.php
<?php

namespace app\classes;

class PDODatabase {

    protected $con;
    private static $instance;
    private $time;
    private $lastInsertId = 0;
    private $realTime = false;

    /** @var list<array{0: string, 1: list<mixed>}> */
    private $recoveryCommands = [];

    /** @var list<array{0: string, 1: list<mixed>}> */
    private $recoveryTransactionCommands = [];

    /** @var int */
    private $transactionDepth = 0;

    /** @var string|null */
    private $recoveryDatabaseName;

    protected function __construct() {
        try {
            $this->con = new \PDO(\app\constants\PDODatabaseConfig::DNS, \app\constants\PDODatabaseConfig::USER, \app\constants\PDODatabaseConfig::PASS);
            $this->con->query('SET NAMES ' . \app\constants\Config::DB_NAMES);
            $this->time = date("Y-m-d H:i:s");
            $this->recoveryDatabaseName = $this->resolveRecoveryDatabaseName();
            register_shutdown_function(function () {
                $this->flushRecoveryLog();
            });
        } catch (\PDOException $ex) {
            printError($ex->getMessage());
            die();
        }
    }

    /**
     * @return PDODatabase
     */
    public static function getInstance() {
        if (PDODatabase::$instance == NULL) {
            PDODatabase::$instance = new PDODatabase();
        }
        return PDODatabase::$instance;
    }

    /**
     * @return \PDO
     */
    public function getConnection() {
        return $this->con;
    }

    /**
     * Add new record to database.
     * @param string $table <p>database table name</p>   
     * @param array $dataArray <p>array of variables to insert (columnName => value)</p>   
     * @param string $excludeFromDataArray <p>array of variables to exclude in update given in $dataArray (columnName1, columnName2, ...)</p> 
     * @param string $idColumnName <p>identificator column name</p>        
     * @return void <p>No value is returned.</p>     
     */
    public function addRecord($table, array $dataArray, array $excludeFromDataArray = array(), $idColumnName = "id") {
        $columns = "";
        $values = "";
        $command = "INSERT INTO " . $table . "(";
        foreach ($dataArray as $var => $post) {
            if (!in_array($var, $excludeFromDataArray)) {
                $columns .= "`" . $var . "`, ";
                $values .= ":" . $var . ", ";
                $dataArray[":" . $var] = str_replace(" ", "", $dataArray[$var] === "") ? null : $dataArray[$var];
                unset($dataArray[$var]);
            } else {
                unset($dataArray[$var]);
            }
        }
        $sql = $command . substr($columns, 0, -2) . ") VALUES(" . substr($values, 0, -2) . ");";


        $query = $this->con->prepare($sql);

        foreach ($dataArray as $key => &$val) {
            $query->bindParam($key, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
        }

        if (!$query->execute()) {
            throw new \Exception(trim($query->errorInfo()[2]) === "" ? $query->errorInfo()[0] : $query->errorInfo()[2], $query->errorInfo()[1]);
        }
        $this->queueRecoveryLogCommand($sql, $dataArray);

        if ($idColumnName !== false) {
            $time = $this->getTime();
            $email = $this->getLoggedEmail();
            $id = $this->getLastInsertId();
            $idCondition = " WHERE " . $idColumnName . "=:" . $idColumnName;

            try {
                $sql2 = "UPDATE " . $table . " SET last_update=:last_update " . $idCondition;
                $query2 = $this->con->prepare($sql2);
                $query2->bindParam(":last_update", $time, \PDO::PARAM_STR);
                $query2->bindParam(":" . $idColumnName, $id, is_int($id) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
                if (@$query2->execute()) {
                    $this->queueRecoveryLogCommand($sql2, [
                        ':last_update' => $time,
                        ':' . $idColumnName => $id,
                    ]);
                }
            } catch (\Exception $ex) {
                // no last update column
            }

            if ($this->getLoggedEmail() !== false) {
                try {
                    $sql3 = "UPDATE " . $table . " SET last_update_by=:last_update_by" . $idCondition;
                    $query3 = $this->con->prepare($sql3);
                    $query3->bindParam(":last_update_by", $email, \PDO::PARAM_STR);
                    $query3->bindParam(":" . $idColumnName, $id, is_int($id) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
                    if (@$query3->execute()) {
                        $this->queueRecoveryLogCommand($sql3, [
                            ':last_update_by' => $email,
                            ':' . $idColumnName => $id,
                        ]);
                    }
                } catch (\Exception $ex) {
                    //no last update by column
                }
                try {
                    $sql4 = "UPDATE " . $table . " SET created_by=:created_by" . $idCondition;
                    $query4 = $this->con->prepare($sql4);
                    $query4->bindParam(":created_by", $email, \PDO::PARAM_STR);
                    $query4->bindParam(":" . $idColumnName, $id, is_int($id) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
                    if (@$query4->execute()) {
                        $this->queueRecoveryLogCommand($sql4, [
                            ':created_by' => $email,
                            ':' . $idColumnName => $id,
                        ]);
                    }
                } catch (\Exception $ex) {
                    //no created by column
                }
            }
            try {
                $sql5 = "UPDATE " . $table . " SET created=:created " . $idCondition;
                $query5 = $this->con->prepare($sql5);
                $query5->bindParam(":created", $time, \PDO::PARAM_STR);
                $query5->bindParam(":" . $idColumnName, $id, is_int($id) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
                if (@$query5->execute()) {
                    $this->queueRecoveryLogCommand($sql5, [
                        ':created' => $time,
                        ':' . $idColumnName => $id,
                    ]);
                }
            } catch (\Exception $ex) {
                //no created column
            }
        }
    }

    /**
     * Delete element from database. Not recommended to use this function!
     * @return void <p>No value is returned.</p>     
     */
    public function deleteRecord($table, $id, $idColumnName = "id") {
        $sql = "DELETE FROM " . $table . " WHERE " . $idColumnName . "= :" . $idColumnName . ";";
        $params = array(":" . $idColumnName => $id);
        $query = $this->con->prepare($sql);
        if ($query->execute($params)) {
            $this->queueRecoveryLogCommand($sql, $params);
            return true;
        }
        return false;
    }

    /**
     * Updates element in database.
     * @param string $table <p>database table name</p>    
     * @param array $dataArray <p>array of variables to update (columnName => value)</p>   
     * @param mixed $id <p>id value of element to update</p>
     * @param mixed $idColumnName <p>identificator column name</p>      
     * @param string $exclude <p>array of variables to exclude in update given in $dataArray (columnName1, columnName2, ...)</p>    
     * @return void <p>No value is returned.</p>   
     */
    public function updateRecord($table, array $dataArray, $id, $idColumnName, array $exclude = array()) {
        $command = "UPDATE " . $table . " SET ";
        foreach ($dataArray as $var => $post) {
            if (!in_array($var, $exclude)) {
                $command .= "`" . $var . "`" . " = :" . $var . ", ";
                $dataArray[":" . $var] = str_replace(" ", "", $post === "") ? null : $post;
            }
            unset($dataArray[$var]);
        }
        $dataArray[":" . $idColumnName] = $id;

        $sql = substr($command, 0, -2);

        if (is_array($id)) {
            $c = 0;
            $ids = array();
            foreach ($id as $key => $val) {
                $c++;
                $dataArray[":id" . $c] = $val;
                $ids[] = ":id" . $c;
            }
            $idCondition = " WHERE " . $idColumnName . " IN(" . implode(", ", $ids) . ")";
        } else {
            $ids = array(":" . $idColumnName => $id);
            $dataArray[":" . $idColumnName] = $id;
            $idCondition = " WHERE " . $idColumnName . " = :" . $idColumnName . ";";
        }

        $sql .= $idCondition;

        $query = $this->con->prepare($sql);

        foreach ($dataArray as $key => &$val) {
            $query->bindParam($key, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
        }

        if (!$query->execute()) {
            throw new \Exception(trim($query->errorInfo()[2]) === "" ? $query->errorInfo()[0] : $query->errorInfo()[2], $query->errorInfo()[1]);
        }
        $this->queueRecoveryLogCommand($sql, $dataArray);

        $time = $this->getTime();
        $email = $this->getLoggedEmail();

        try {
            $sql2 = "UPDATE " . $table . " SET last_update=:last_update " . $idCondition;
            $query2 = $this->con->prepare($sql2);
            $query2->bindParam(":last_update", $time, \PDO::PARAM_STR);
            foreach ($ids as $key => &$val) {
                $query2->bindParam($key, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
            }
            if (@$query2->execute()) {
                $metaParams = [':last_update' => $time];
                foreach ($ids as $key => $val) {
                    $metaParams[$key] = $val;
                }
                $this->queueRecoveryLogCommand($sql2, $metaParams);
            }
        } catch (\Exception $ex) {
            //no last update column
        }

        if ($this->getLoggedEmail() !== false) {
            try {
                $sql3 = "UPDATE " . $table . " SET last_update_by=:last_update_by" . $idCondition;
                $query3 = $this->con->prepare($sql3);
                $query3->bindParam(":last_update_by", $email, \PDO::PARAM_STR);
                foreach ($ids as $key => &$val) {
                    $query3->bindParam($key, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
                }
                if (@$query3->execute()) {
                    $metaParams = [':last_update_by' => $email];
                    foreach ($ids as $key => $val) {
                        $metaParams[$key] = $val;
                    }
                    $this->queueRecoveryLogCommand($sql3, $metaParams);
                }
            } catch (\Exception $ex) {
                //no last update by column
            }
        }
    }

    /**
     * Get identificator value (auto increment column) of last inserted record to db.    
     * @return int <p>id value</p>   
     */
    public function getLastInsertId() {
        $lastInsertId = $this->con->lastInsertId();
        if (intval($lastInsertId) !== 0 || !is_numeric($lastInsertId)) {
            $this->lastInsertId = $lastInsertId;
        }
        return $this->lastInsertId;
    }

    /**
     * Get max value in numeric column.   
     * @param string $table <p>table name</p> 
     * @param string $column <p>column name</p> 
     * @return int <p>max value</p>   
     */
    public function getMaxValue($table, $column) {
        $sql = "SELECT MAX($column) FROM $table LIMIT 1";
        $query = $this->con->prepare($sql);
        if (!$query->execute()) {
            return NULL;
        }
        $max = $query->fetch();
        if (empty($max[0])) {
            $value = NULL;
        } else {
            $value = $max[0];
        }
        return $value;
    }

    public function getRow($table, $id, $idColumnName = "id", $condition = false, array $bindArray = array(), $customSelection = false) {
        if ($condition === false && $customSelection === false) {
            $sql = "SELECT * FROM $table WHERE $idColumnName = :" . $idColumnName;
            $query = $this->con->prepare($sql);
            $bindColumnName = ":" . $idColumnName;
            $query->bindParam($bindColumnName, $id, is_int($id) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
        } else if ($condition !== false) {
            $sql = "SELECT * FROM $table WHERE " . $idColumnName . "= :" . $idColumnName . " AND " . $condition;
            $query = $this->con->prepare($sql);
            foreach ($bindArray as $key => $val) {
                $bindArray[":" . $key] = $val;
                unset($bindArray[$key]);
            }
        } else {
            $sql = $customSelection;
            $query = $this->con->prepare($sql);
            foreach ($bindArray as $key => $val) {
                $bindArray[":" . $key] = $val;
                unset($bindArray[$key]);
            }
        }

//        if ($table === "") {
//            echo $sql;
//            var_dump($bindArray);            
//        }

        if (!$query->execute($bindArray)) {
            throw new \Exception(trim($query->errorInfo()[2]) === "" ? $query->errorInfo()[0] : $query->errorInfo()[2] . ": " . $id, $query->errorInfo()[1]);
        }       
      
        return $query->fetch(\PDO::FETCH_ASSOC);
    }

    public function getRows($table, $idColumn, $customSelection = false, array $bindArray = array(), $fetch_assoc = false, $condition = false) {
        if ($condition === false) {
            $sql = ($customSelection === false) ? "SELECT * FROM " . $table : $customSelection;
        } else {
            $sql = "SELECT * FROM " . $table . " " . $condition;
        }

        $query = $this->con->prepare($sql);
        foreach ($bindArray as $key => $val) {
            $bindArray[":" . $key] = $val;
            unset($bindArray[$key]);
        }
        $rows = array();
        $query->execute($bindArray);
        if (!$query->execute()) {
            throw new \Exception(trim($query->errorInfo()[2]) === "" ? $query->errorInfo()[0] : $query->errorInfo()[2], $query->errorInfo()[1]);
        }

        if ($fetch_assoc) {
            return $query;
        }

        if (is_array($idColumn)) {
            foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $key => $val) {
                if (!isset($rows[$val[$idColumn[0]]]) || !is_array($rows[$val[$idColumn[0]]])) {
                    $rows[$val[$idColumn[0]]] = array();
                }
                $rows[$val[$idColumn[0]]][$val[$idColumn[1]]] = $val;
            }
        } else {
            foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $key => $val) {
                $rows[$val[$idColumn]] = $val;
            }
        }
        return $rows;
    }

    /**
     * Get single value from database according to condition. LIMIT 1 is automatically added to query.   
     * @param string $sql <p>sql query string</p> 
     * @param array $bindArray <p>array ov bind variables</p> 
     * @return mixed <p>Returns selected value or NULL if no value was selected.</p>   
     */
    public function getValue($sql, array $bindArray = array()) {
        $query = $this->con->prepare($sql . " LIMIT 1");
        foreach ($bindArray as $key => &$val) {
            $query->bindParam(":" . $key, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
        }
        if (!$query->execute()) {
            throw new \Exception(trim($query->errorInfo()[2]) === "" ? $query->errorInfo()[0] : $query->errorInfo()[2], $query->errorInfo()[1]);
        }
        $row = $query->fetch();
        if (is_array($row)) {
            return $row[0];
        }
        return NULL;
    }

    /**
     * Execute SQL query.  
     * @param string $sql <p>sql query string</p> 
     * @param array $bindArray <p>array ov bind variables</p>  
     * @return void <p>No value is returned.</p>   
     */
    public function sqlCommand($sql, $bindArray) {
        $query = $this->con->prepare($sql);
        if (!$query->execute($bindArray)) {
            throw new \Exception(trim($query->errorInfo()[2]) === "" ? $query->errorInfo()[0] : $query->errorInfo()[2], $query->errorInfo()[1]);
        }
        $this->queueRecoveryLogCommand($sql, is_array($bindArray) ? $bindArray : []);
    }

    /**
     * Get time of instance initialization.  
     * @param bool $integer <p>return time as int value</p> 
     * @return mixed <p>Returns time int value or date and time as string.</p>   
     */
    public function getTime($integer = false) {
        if ($this->realTime) {
            return $integer ? time() : date("Y-m-d H:i:s");
        } else {
            return $integer ? strtotime($this->time) : $this->time;
        }
    }

    public function getLoggedEmail() {
        $email = isset($_SESSION["email"]) ? $_SESSION["email"] : false;
        if ($email === false && key_exists("HTTP_HOST", $_SERVER)) {
            try {
                $user = BasicUser::getLoggedUser();
                $email = $user->_get("email");
            } catch (\Exception $ex) {
                
            }
        }
        return $email;
    }

    public function enableRealTime() {
        $this->realTime = true;
    }

    public function disableRealTime() {
        $this->realTime = false;
    }

    public function startTransaction() {
        $this->sqlCommand("SET autocommit = 0; START TRANSACTION;", array());
        $this->transactionDepth++;
    }

    public function commit() {
        $this->sqlCommand("COMMIT; SET autocommit = 1;", array());
        if ($this->transactionDepth <= 0) {
            return;
        }
        $this->transactionDepth--;
        if ($this->transactionDepth === 0 && $this->recoveryTransactionCommands !== []) {
            foreach ($this->recoveryTransactionCommands as $command) {
                $this->recoveryCommands[] = $command;
            }
            $this->recoveryTransactionCommands = [];
        }
    }

    public function rollback() {
        $this->sqlCommand("ROLLBACK; SET autocommit = 1;", array());
        $this->transactionDepth = 0;
        $this->recoveryTransactionCommands = [];
    }

    /**
     * Buffer a successful data-modifying statement for the request recovery log.
     *
     * @param string $sql
     * @param array<string|int, mixed> $params
     */
    private function queueRecoveryLogCommand($sql, array $params) {
        if (!$this->isDataModifyingSql($sql) || $this->shouldSkipRecoveryLog($sql)) {
            return;
        }

        $command = $this->formatRecoveryCommand($sql, $params);
        if ($this->transactionDepth > 0) {
            $this->recoveryTransactionCommands[] = $command;
            return;
        }

        $this->recoveryCommands[] = $command;
    }

    /**
     * Write buffered recovery commands to disk once per request (JSON Lines).
     * Uncommitted transaction commands are discarded.
     */
    private function flushRecoveryLog() {
        $this->recoveryTransactionCommands = [];

        if ($this->recoveryCommands === []) {
            return;
        }

        $dir = \app\constants\DbChangelogConfig::getLogDirectory();
        if (!is_dir($dir) && !@mkdir($dir, 0755, true) && !is_dir($dir)) {
            return;
        }

        $entry = [
            'time' => $this->formatRecoveryTimestamp(microtime(true)),
            'database' => (string) ($this->recoveryDatabaseName ?? ''),
            'commands' => $this->recoveryCommands,
        ];

        $email = $this->getLoggedEmail();
        if ($email !== false) {
            $entry['user'] = $email;
        }

        $json = json_encode($entry, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        if ($json === false) {
            $this->recoveryCommands = [];
            return;
        }

        $file = $dir . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log';
        @file_put_contents($file, $json . "\n", FILE_APPEND | LOCK_EX);
        $this->recoveryCommands = [];
    }

    /**
     * @param string $sql
     */
    private function isDataModifyingSql($sql) {
        return (bool) preg_match('/^\s*(INSERT|UPDATE|DELETE)\b/i', (string) $sql);
    }

    /**
     * Apply {@see \app\constants\DbChangelogConfig} table/column blacklists.
     *
     * @param string $sql
     */
    private function shouldSkipRecoveryLog($sql) {
        $sql = (string) $sql;
        $table = $this->extractRecoveryTableName($sql);
        if ($table !== null && \app\constants\DbChangelogConfig::isTableBlacklisted($table)) {
            return true;
        }

        if (!preg_match('/^\s*UPDATE\b/i', $sql)) {
            return false;
        }

        $columns = $this->extractUpdateSetColumns($sql);
        return \app\constants\DbChangelogConfig::areOnlyBlacklistedColumns($table, $columns);
    }

    /**
     * @param string $sql
     * @return string|null
     */
    private function extractRecoveryTableName($sql) {
        if (preg_match('/^\s*INSERT\s+INTO\s+`?([a-zA-Z0-9_]+)`?/i', $sql, $matches)) {
            return $matches[1];
        }
        if (preg_match('/^\s*UPDATE\s+`?([a-zA-Z0-9_]+)`?/i', $sql, $matches)) {
            return $matches[1];
        }
        if (preg_match('/^\s*DELETE\s+FROM\s+`?([a-zA-Z0-9_]+)`?/i', $sql, $matches)) {
            return $matches[1];
        }

        return null;
    }

    /**
     * @param string $sql
     * @return list<string>
     */
    private function extractUpdateSetColumns($sql) {
        if (!preg_match('/^\s*UPDATE\b.+?\bSET\s+(.+?)(?:\s+WHERE\b|\s*$)/is', $sql, $matches)) {
            return [];
        }

        if (!preg_match_all('/`?([a-zA-Z_][a-zA-Z0-9_]*)`?\s*=/', $matches[1], $columnMatches)) {
            return [];
        }

        return array_values(array_unique($columnMatches[1]));
    }

    /**
     * Normalize SQL + params to a compact replay tuple: [sqlWithPlaceholders, params].
     *
     * @param string $sql
     * @param array<string|int, mixed> $params
     * @return array{0: string, 1: list<mixed>}
     */
    private function formatRecoveryCommand($sql, array $params) {
        $sql = (string) $sql;
        $normalized = [];
        foreach ($params as $key => $value) {
            $normalizedValue = $this->normalizeRecoveryParamValue($value);
            if (is_int($key)) {
                $normalized[$key] = $normalizedValue;
                continue;
            }
            $name = (string) $key;
            if ($name !== '' && $name[0] !== ':') {
                $name = ':' . $name;
            }
            $normalized[$name] = $normalizedValue;
        }

        if (!preg_match('/:[a-zA-Z_][a-zA-Z0-9_]*/', $sql)) {
            return [$sql, array_values($normalized)];
        }

        $ordered = [];
        $convertedSql = preg_replace_callback(
            '/:([a-zA-Z_][a-zA-Z0-9_]*)/',
            function ($matches) use ($normalized, &$ordered) {
                $name = ':' . $matches[1];
                if (array_key_exists($name, $normalized)) {
                    $ordered[] = $normalized[$name];
                } else {
                    $ordered[] = null;
                }
                return '?';
            },
            $sql
        );

        return [(string) $convertedSql, $ordered];
    }

    /**
     * @param mixed $value
     * @return mixed
     */
    private function normalizeRecoveryParamValue($value) {
        if ($value === null || is_bool($value) || is_int($value) || is_float($value) || is_string($value)) {
            return $value;
        }
        if (is_array($value)) {
            return $value;
        }
        if (is_object($value) && method_exists($value, '__toString')) {
            return (string) $value;
        }

        return null;
    }

    /**
     * @param float $microtime
     */
    private function formatRecoveryTimestamp($microtime) {
        $seconds = (int) floor($microtime);
        $fraction = (int) round(($microtime - $seconds) * 1000000);
        if ($fraction >= 1000000) {
            $seconds++;
            $fraction = 0;
        }

        return date('Y-m-d\TH:i:s', $seconds) . sprintf('.%06d', $fraction);
    }

    private function resolveRecoveryDatabaseName() {
        if (defined('PDO_DATABASE_CONFIG_DB_NAME')) {
            return (string) PDO_DATABASE_CONFIG_DB_NAME;
        }

        $dsn = (string) \app\constants\PDODatabaseConfig::DNS;
        if (preg_match('/dbname=([^;]+)/i', $dsn, $matches)) {
            return $matches[1];
        }

        return '';
    }

}

Youez - 2016 - github.com/yon3zu
LinuXploit