From 0dfd613aec2e0490f7711af00d33672e58a90ebc Mon Sep 17 00:00:00 2001
From: ztk <support@ztk.me>
Date: Wed, 14 Nov 2018 23:40:36 +0100
Subject: [PATCH] consider change stuff to pdo aswell

---
 adcheck.php             |   6 +-
 adclick.php             |   7 +-
 class/campaigns.php     |  32 +++++
 class/database.php      | 281 ++++++++++++++++++++++++++++++++++++++++
 class/databaseTable.php | 114 ++++++++++++++++
 ext/ap/ads.inc.php      |  26 ----
 lib/datenbank.inc.php   |  25 +++-
 lib/functions.lib.php   |   9 ++
 8 files changed, 464 insertions(+), 36 deletions(-)
 create mode 100644 class/campaigns.php
 create mode 100644 class/database.php
 create mode 100644 class/databaseTable.php

diff --git a/adcheck.php b/adcheck.php
index 388fc4a..71ee05e 100644
--- a/adcheck.php
+++ b/adcheck.php
@@ -9,7 +9,9 @@ require ('ext/ap/ads.inc.php');
 list($art, $tan) = explode('-', $_GET['data']); // yeah sorry ;)
 $art = base64_decode($art);
 $tan = base64_decode($tan);
-$kampdaten = getAdDataByArtAndTan( $art, $tan );
+
+$kampdaten_rows = $campaigns->getCampaignByTanAndType( $tan, $art );
+$kampdaten = $kampdaten_rows[0];
 
 $result_color = 'red';
 
@@ -32,7 +34,7 @@ if( $tan == $_SESSION['current_ad']['tan'] &&
     <body bgcolor="<?php echo $result_color; ?>">
 
         <?php if( 'green' == $result_color ) { ?>
-        Diese Anzeige wurde dir mit <?php echo $kampdaten['verdienst'] .' '. $pageconfig['waehrung']; ?> verg&uuml;tet.
+        Diese Anzeige wurde dir mit <?php echo $kampdaten->verdienst .' '. $pageconfig['waehrung']; ?> verg&uuml;tet.
         <?php } else { ?>
         Nope, das war nix
         <?php } ?>
diff --git a/adclick.php b/adclick.php
index 9abdf60..318daae 100644
--- a/adclick.php
+++ b/adclick.php
@@ -10,7 +10,8 @@ list($art, $tan) = explode('-', $_GET['data']); // yeah sorry ;)
 $art = base64_decode($art);
 $tan = base64_decode($tan);
 
-$kampdaten = getAdDataByArtAndTan( $art, $tan );
+$kampdaten_rows = $campaigns->getCampaignByTanAndType( $tan, $art );
+$kampdaten = $kampdaten_rows[0];
 // TODO prevent malicious ziel urls
 
 invalidateAlreadyRunningAd();
@@ -21,7 +22,7 @@ setCurrentRunningAd( $art, $tan );
         <!-- never is old spec but will be ignored by new browsers //-->
         <meta name="referrer" content="never">
         <meta name="referrer" content="no-referrer" />
-        <meta http-equiv="refresh" content="0; URL=<?php echo $kampdaten['ziel']; ?>">
+        <meta http-equiv="refresh" content="0; URL=<?php echo $kampdaten->ziel; ?>">
         <title>Anzeige</title>
     </head>
     <body>
@@ -38,6 +39,6 @@ setCurrentRunningAd( $art, $tan );
             return true;
         }
       </script>
-      <a href="<?php echo $kampdaten['ziel']; ?>" rel="noopener noreferrer nofollow" onclick="notify();" >Hier weiter, falls keine automatische Weiterleitung erfolgt.</a>
+      <a href="<?php echo $kampdaten->ziel; ?>" rel="noopener noreferrer nofollow" onclick="notify();" >Hier weiter, falls keine automatische Weiterleitung erfolgt.</a>
     </body>
 </html>
diff --git a/class/campaigns.php b/class/campaigns.php
new file mode 100644
index 0000000..ca5973c
--- /dev/null
+++ b/class/campaigns.php
@@ -0,0 +1,32 @@
+<?php
+
+class Campaigns
+{
+
+    private $database;
+
+    public function __construct( $database )
+    {
+        $this->database = $database;
+    }
+
+
+    public function getCampaignByTanAndType( $tan, $type, $status = false )
+    {
+        $where_status = ( false !== $status ) ? ' AND `status` = :status ' : '';
+
+        $sql = '`uid`, `tan`, `kid`, `ziel`, `banner`, `verdienst`, `preis`, `aufendhalt`, `menge`, `reload`, `sponsor`, `werbeart`, `status`
+                FROM `'.DB_PREFIX.'_gebuchte_werbung` WHERE `tan` = :tan AND `werbeart` = :type '.$where_status.' LIMIT 1';
+        $sql_params = array(
+                           ':tan'     => $tan,
+                           ':type'    => $type,
+                      );
+        if( false !== $status )
+        {
+            $sql_params[':status'] = $status;
+        }
+
+        return $this->database->select($sql, $sql_params);
+    }
+
+}
diff --git a/class/database.php b/class/database.php
new file mode 100644
index 0000000..a0605bd
--- /dev/null
+++ b/class/database.php
@@ -0,0 +1,281 @@
+<?php
+// https://raw.githubusercontent.com/daveismyname/pdo-wrapper/master/database.php
+
+require_once( __DIR__ .'/databaseTable.php' );
+
+class DaveDatabase extends PDO
+{
+    /**
+     * @var array Array of saved databases for reusing
+     */
+    protected static $instances = array();
+
+    /**
+     * Static method get
+     *
+     * @param  array $group
+     * @return \helpers\database
+     */
+    public static function get($group = false)
+    {
+        // Determining if exists or it's not empty, then use default group defined in config
+        $group = !$group ? array (
+            'type' => DB_TYPE,
+            'host' => DB_HOST,
+            'name' => DB_NAME,
+            'user' => DB_USER,
+            'pass' => DB_PASS
+        ) : $group;
+
+        // Group information
+        $type = $group['type'];
+        $host = $group['host'];
+        $name = $group['name'];
+        $user = $group['user'];
+        $pass = $group['pass'];
+
+        // ID for database based on the group information
+        $id = "$type.$host.$name.$user.$pass";
+
+        // Checking if the same
+        if (isset(self::$instances[$id])) {
+            return self::$instances[$id];
+        }
+
+        $instance = new Database("$type:host=$host;dbname=$name;charset=utf8", $user, $pass);
+        $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+        // Setting Database into $instances to avoid duplication
+        self::$instances[$id] = $instance;
+
+        //return the pdo instance
+        return $instance;
+
+    }
+
+    /**
+     * run raw sql queries
+     * @param  string $sql sql command
+     * @return none
+     */
+    public function raw($sql)
+    {
+        $this->query($sql);
+    }
+
+    /**
+     * method for selecting records from a database
+     * @param  string $sql       sql query
+     * @param  array  $array     named params
+     * @param  object $fetchMode
+     * @param  string $class     class name
+     * @return array            returns an array of records
+     */
+    public function select($sql, $array = array(), $fetchMode = PDO::FETCH_OBJ, $class = '')
+    {
+         // Append select if it isn't appended.
+        if (strtolower(substr($sql, 0, 7)) !== 'select ') {
+            $sql = "SELECT " . $sql;
+        }
+
+        $stmt = $this->prepare($sql);
+        foreach ($array as $key => $value) {
+            if (is_int($value)) {
+                $stmt->bindValue("$key", $value, PDO::PARAM_INT);
+            } else {
+                $stmt->bindValue("$key", $value);
+            }
+        }
+
+        $stmt->execute();
+
+        if ($fetchMode === PDO::FETCH_CLASS) {
+            return $stmt->fetchAll($fetchMode, $class);
+        } else {
+            return $stmt->fetchAll($fetchMode);
+        }
+    }
+    
+    /**
+    * Count method
+    * @param  string $table table name
+    * @param  string $column optional
+    */
+    public function count($table, $column= 'id') {
+            $stmt = $this->prepare("SELECT $column FROM $table");
+            $stmt->execute();		      
+            return $stmt->rowCount();
+    }
+
+    /**
+     * insert method
+     * @param  string $table table name
+     * @param  array $data  array of columns and values
+     */
+    public function insert($table, $data)
+    {
+        ksort($data);
+
+        $fieldNames = implode(',', array_keys($data));
+        $fieldValues = ':'.implode(', :', array_keys($data));
+
+        $stmt = $this->prepare("INSERT INTO $table ($fieldNames) VALUES ($fieldValues)");
+
+        foreach ($data as $key => $value) {
+            $stmt->bindValue(":$key", $value);
+        }
+
+        $stmt->execute();
+        return $this->lastInsertId();
+    }
+
+    /**
+     * update method
+     * @param  string $table table name
+     * @param  array $data  array of columns and values
+     * @param  array $where array of columns and values
+     */
+    public function update($table, $data, $where)
+    {
+        ksort($data);
+
+        $fieldDetails = null;
+        foreach ($data as $key => $value) {
+            $fieldDetails .= "$key = :$key,";
+        }
+        $fieldDetails = rtrim($fieldDetails, ',');
+
+        $whereDetails = null;
+        $i = 0;
+        foreach ($where as $key => $value) {
+            if ($i == 0) {
+                $whereDetails .= "$key = :$key";
+            } else {
+                $whereDetails .= " AND $key = :$key";
+            }
+            $i++;
+        }
+        $whereDetails = ltrim($whereDetails, ' AND ');
+
+        $stmt = $this->prepare("UPDATE $table SET $fieldDetails WHERE $whereDetails");
+
+        foreach ($data as $key => $value) {
+            $stmt->bindValue(":$key", $value);
+        }
+
+        foreach ($where as $key => $value) {
+            $stmt->bindValue(":$key", $value);
+        }
+
+        $stmt->execute();
+        return $stmt->rowCount();
+    }
+
+    /**
+     * Delete method
+     * @param  string $table table name
+     * @param  array $data  array of columns and values
+     * @param  array $where array of columns and values
+     * @param  integer $limit limit number of records
+     */
+    public function delete($table, $where, $limit = 1)
+    {
+        ksort($where);
+
+        $whereDetails = null;
+        $i = 0;
+        foreach ($where as $key => $value) {
+            if ($i == 0) {
+                $whereDetails .= "$key = :$key";
+            } else {
+                $whereDetails .= " AND $key = :$key";
+            }
+            $i++;
+        }
+        $whereDetails = ltrim($whereDetails, ' AND ');
+
+        //if limit is a number use a limit on the query
+        if (is_numeric($limit)) {
+            $uselimit = "LIMIT $limit";
+        }
+
+        $stmt = $this->prepare("DELETE FROM $table WHERE $whereDetails $uselimit");
+
+        foreach ($where as $key => $value) {
+            $stmt->bindValue(":$key", $value);
+        }
+
+        $stmt->execute();
+        return $stmt->rowCount();
+    }
+
+    /**
+     * truncate table
+     * @param  string $table table name
+     */
+    public function truncate($table)
+    {
+        return $this->exec("TRUNCATE TABLE $table");
+    }
+}
+
+
+class Database extends DaveDatabase
+{
+    private $table_objects = array();
+
+    public function getTable( $table_name )
+    {
+        if( !isset($this->table_objects[$table_name]) )
+        {
+            $this->loadTableObject( $table_name );
+        }
+        return ( isset($this->table_objects[$table_name]) ) ? $this->table_objects[$table_name] : false;
+    }
+
+    private function loadTableObject( $table_name )
+    {
+        $result = false;
+
+        $filepath = __DIR__ .'/database/'.$table_name.'.ext.php';
+
+        if( !file_exists( $filepath ) )
+        {
+            $this->tryCreateTableDefinition( $table_name );
+        }
+
+        if( file_exists( $filepath ) )
+        {
+            require_once( $filepath );
+            $class_name = 'Table'. $table_name;
+            if( class_exists( $class_name ) )
+            {
+                $this->table_objects[$table_name] = new $class_name();
+                $result = true;
+            }
+        }
+        return $result;
+    }
+
+
+    private function tryCreateTableDefinition( $table_name )
+    {
+        $table_class = new DatabaseTable($this, $table_name);
+        $table_class->getColumnMeta();
+        var_dump($table_class->fields);
+        var_dump($table_class->field_meta);
+        var_dump($table_class->primary_key);
+    }
+
+
+    /*
+    * $db->select("`username` FROM `members` WHERE `memberID` = :id and `email` = :email", array(':id' => 1, ':email' => 'someone@domain.com'));
+    * $db->selectAll("members", "WHERE `memberID` = :id and `email` = :email", array(':id' => 1, ':email' => 'someone@domain.com'));
+    */
+    public function selectAll($sql, $array = array(), $fetchMode = PDO::FETCH_OBJ, $class = '')
+    {
+
+
+    }
+
+}
diff --git a/class/databaseTable.php b/class/databaseTable.php
new file mode 100644
index 0000000..3b48bbe
--- /dev/null
+++ b/class/databaseTable.php
@@ -0,0 +1,114 @@
+<?php
+
+class DatabaseTable
+{
+
+    public $fields      = array();
+    public $field_meta  = array();
+    public $primary_key = NULL;
+
+    private $database;
+    private $table_name;
+
+    public function __construct( $database, $table_name )
+    {
+        $this->database   = $database;
+        $this->table_name = $table_name;
+    }
+
+    /**
+    * Will attempt to bind columns with datatypes based on parts of the column type name
+    * Any part of the name below will be picked up and converted unless otherwise sepcified
+    *     Example: 'VARCHAR' columns have 'CHAR' in them, so 'char' => PDO::PARAM_STR will convert
+    * all columns of that type to be bound as PDO::PARAM_STR
+    * If there is no specification for a column type, column will be bound as PDO::PARAM_STR
+    */
+    protected $pdo_bind_types = array(
+                                'char'   => PDO::PARAM_STR,
+                                'int'    => PDO::PARAM_INT,
+                                'bool'   => PDO::PARAM_BOOL,
+                                'date'   => PDO::PARAM_STR,
+                                'time'   => PDO::PARAM_INT,
+                                'text'   => PDO::PARAM_STR,
+                                'blob'   => PDO::PARAM_LOB,
+                                'binary' => PDO::PARAM_LOB
+    );
+
+
+    /**
+    * Parse PDO-produced column type
+    * [internal function]
+    */
+    protected function parseColumnType($col_type)
+    {
+        $col_info = array();
+        $col_parts = explode(" ", $col_type);
+        if( $fparen = strpos($colParts[0], "(") )
+        {
+            $col_info['type']       = substr($col_parts[0], 0, $fparen);
+            $col_info['pdo_type']   = '';
+            $col_info['length']     = str_replace(")", "", substr($col_parts[0], $fparen+1));
+            $col_info['attributes'] = isset($col_parts[1]) ? $col_parts[1] : NULL;
+        }
+        else
+        {
+            $col_info['type'] = $col_parts[0];
+        }
+
+        // PDO Bind types
+        $pdo_type = '';
+        foreach($this->pdo_bind_types as $pKey => $pType)
+        {
+            if(strpos(' '.strtolower($col_info['type']).' ', $pKey))
+            {
+                $col_info['pdo_type'] = $pType;
+                break;
+            }
+            else
+            {
+                $col_info['pdo_type'] = PDO::PARAM_STR;
+            }
+        }
+        return $col_info;
+    }
+
+
+    /**
+    * Automatically get column metadata
+    */
+    protected function getColumnMeta($refresh = false)
+    {
+        if( $refresh )
+        {
+            // Clear any previous column/field info
+            $this->fields      = array();
+            $this->field_meta  = array();
+            $this->primary_key = NULL;
+        }
+
+        // Automatically retrieve column information if column info not specified
+        if( count($this->fields) == 0 || count($this->field_meta) == 0 ) 
+        { 
+            // Fetch all columns and store in $this->fields
+            // TODO prepared statement ...
+            $columns = $this->database->query("SHOW COLUMNS FROM " . $this->table_name, PDO::FETCH_ASSOC);
+            foreach( $columns as $key => $col )
+            {   
+                // Insert into fields array
+                $col_name = $col['Field'];
+                $this->fields[$col_name] = $col;
+                if( $col['Key'] == "PRI" && empty($this->primary_key) )
+                {   
+                    $this->primary_key = $col_name;
+                }   
+
+                // Set field types
+                $col_type = $this->parseColumnType($col['Type']);
+                $this->field_meta[$col_name] = $col_type;
+            }   
+        }   
+        return true;
+    }
+
+
+}
diff --git a/ext/ap/ads.inc.php b/ext/ap/ads.inc.php
index 89007c0..1a7d51b 100644
--- a/ext/ap/ads.inc.php
+++ b/ext/ap/ads.inc.php
@@ -138,29 +138,3 @@ function getNewAdData( $dbArt )
     return $result;
 
 }
-
-function getAdDataByArtAndTan( $art, $tan )
-{
-    global $db_prefix, $sql_open;
-    $row = false;
-    $sql = 'SELECT `uid`, `tan`, `kid`, `ziel`, `banner`, `verdienst`, `preis`, `aufendhalt`, `menge`, `reload`, `sponsor`, `werbeart`, `status` FROM `' . $db_prefix . '_gebuchte_werbung` WHERE `tan` = ? AND `werbeart` = ? LIMIT 1';
-
-    $statement = mysqli_prepare( $sql_open, $sql );
-
-    mysqli_stmt_bind_param( $statement, "ss", $tan, $art );
-    if( mysqli_stmt_execute( $statement ) )
-    {
-        mysqli_stmt_store_result( $statement );
-        if ( mysqli_stmt_num_rows( $statement ) > 0 )
-        {
-            $rows = db_fetch( $statement );
-            $row = $rows[0]; // should be there ... > 0
-        }
-    }
-    mysqli_stmt_close( $statement );
-    return $row;
-    
-    //return array( 'uid' => $uid, 'tan' => $tan, 'kid' => $kid, 'ziel' => $ziel, 'banner' => $banner, 'verdienst' => $verdienst, 'preis' => $preis, 'aufendhalt' => $aufendhalt,
-    //                 'menge' =>  $menge, 'reload' => $reload, 'sponsor' => $sponsor, 'werbeart' => $werbeart, 'status' => $status );
-
-}
diff --git a/lib/datenbank.inc.php b/lib/datenbank.inc.php
index f439921..0122673 100644
--- a/lib/datenbank.inc.php
+++ b/lib/datenbank.inc.php
@@ -1,10 +1,25 @@
 <?php
-  require_once( __DIR__ .'/db_config.php' );
+
+require_once( __DIR__ .'/db_config.php' );
+require_once( __DIR__ .'/../class/database.php' );
 	
-	//Datenbankverbindung herstellen
-	$sql_open = @mysqli_connect( DB_HOST, DB_USER, DB_PASS, DB_BASE ) or die('Verbindung zum Mysql Server fehlgeschlagen! <br>Tipp: <a href="http://www.vms-tutorial.de/wiki//Lib/Functions">http://www.vms-tutorial.de/wiki//Lib/Functions</a>');
-  // why?:
-	$sql_base = @mysqli_select_db($sql_open, DB_BASE ) or die("Keine oder falsche Datenbank gewhlt! Tipp: <br><a href='http://www.vms-tutorial.de/wiki//Lib/Functions'>http://www.vms-tutorial.de/wiki//Lib/Functions</a>");
+//Datenbankverbindung herstellen
+$sql_open = @mysqli_connect( DB_HOST, DB_USER, DB_PASS, DB_BASE ) or die('Verbindung zum Mysql Server fehlgeschlagen! <br>Tipp: <a href="http://www.vms-tutorial.de/wiki//Lib/Functions">http://www.vms-tutorial.de/wiki//Lib/Functions</a>');
+// why?:
+$sql_base = @mysqli_select_db($sql_open, DB_BASE ) or die("Keine oder falsche Datenbank gewhlt! Tipp: <br><a href='http://www.vms-tutorial.de/wiki//Lib/Functions'>http://www.vms-tutorial.de/wiki//Lib/Functions</a>");
+
+// please use global $database, $GLOBALs['database'] or pass $database to class/function
+// avoid cluttering the code with silly singleton calls, except when really needed,
+// for example when connectiong to a different database, thank you
+$database = Database::get(
+                array(
+                    'type' => 'mysql',
+                    'host' => DB_HOST,
+                    'name' => DB_BASE,
+                    'user' => DB_USER,
+                    'pass' => DB_PASS,
+                )
+            );
 
 	/**
 	 * db_connect()
diff --git a/lib/functions.lib.php b/lib/functions.lib.php
index 92271e7..a7a61ca 100644
--- a/lib/functions.lib.php
+++ b/lib/functions.lib.php
@@ -1,5 +1,14 @@
 <?php
 
+if( isset($database) )
+{
+    require_once( __DIR__ . '/../class/campaigns.php' );
+    $campaigns = new Campaigns($database);
+
+} else {
+    throw new Exception( 'Please include lib/datenbank.inc.php before lib/functions.lib.php' );
+}
+
 /**
  * create_code()
  *
-- 
GitLab