Example #1
0
function check_device_key($devicekey)
{
    global $mysqli, $redis;
    include "Modules/device/device_model.php";
    $device = new Device($mysqli, $redis);
    $session = $device->devicekey_session($devicekey);
    if (empty($session)) {
        header($_SERVER["SERVER_PROTOCOL"] . " 401 Unauthorized");
        header('WWW-Authenticate: Bearer realm="Device KEY", error="invalid_devicekey", error_description="Invalid device key"');
        print "Invalid device key";
        $log = new EmonLogger(__FILE__);
        $log->error("Invalid device key '" . $devicekey . "'");
        exit;
    }
    return $session;
}
Example #2
0
// OpenEnergyMonitor project:
// http://openenergymonitor.org
define('EMONCMS_EXEC', 1);
$fp = fopen("/var/lock/phpmqtt_input.lock", "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    echo "Already running\n";
    die;
}
chdir(dirname(__FILE__) . "/../");
require "Lib/EmonLogger.php";
require "process_settings.php";
if (!$mqtt_enabled) {
    echo "Error: setting must be true: mqtt_enabled\n";
    die;
}
$log = new EmonLogger(__FILE__);
$log->info("Starting MQTT Input script");
$mysqli = @new mysqli($server, $username, $password, $database);
if ($mysqli->connect_error) {
    $log->error("Can't connect to database:" . $mysqli->connect_error);
    die('Check log\\n');
}
if ($redis_enabled) {
    $redis = new Redis();
    if (!$redis->connect($redis_server['host'], $redis_server['port'])) {
        $log->error("Could not connect to redis at " . $redis_server['host'] . ":" . $redis_server['port']);
        die('Check log\\n');
    }
    if (!empty($redis_server['prefix'])) {
        $redis->setOption(Redis::OPT_PREFIX, $redis_server['prefix']);
    }
Example #3
0
    if (!isset($session['read']) || isset($session['read']) && !$session['read']) {
        // Non authenticated defaults
        $route->controller = $default_controller;
        $route->action = $default_action;
        $route->subaction = "";
    } else {
        // Authenticated defaults
        $route->controller = $default_controller_auth;
        $route->action = $default_action_auth;
        $route->subaction = "";
    }
}
if ($devicekey && !($route->controller == 'input' && ($route->action == 'bulk' || $route->action == 'post'))) {
    header($_SERVER["SERVER_PROTOCOL"] . " 401 Unauthorized");
    print "Unauthorized. Device key autentication only permits input post or bulk actions";
    $log = new EmonLogger(__FILE__);
    $log->error("Unauthorized. Device key autentication only permits input post or bulk actions");
    exit;
}
if ($route->controller == 'input' && $route->action == 'bulk') {
    $route->format = 'json';
} else {
    if ($route->controller == 'input' && $route->action == 'post') {
        $route->format = 'json';
    }
}
// 6) Load the main page controller
$output = controller($route->controller);
// If no controller of this name - then try username
// need to actually test if there isnt a controller rather than if no content
// is returned from the controller.
Example #4
0
<?php

// This code is released under the GNU Affero General Public License.
// OpenEnergyMonitor project:
// http://openenergymonitor.org
define('EMONCMS_EXEC', 1);
$fp = fopen("/home/pi/data/feedrunlock", "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    echo "Already running\n";
    die;
}
chdir("/var/www/emoncms");
require "Modules/log/EmonLogger.php";
require "process_settings.php";
$log = new EmonLogger(__FILE__);
$log->set_logfile("/var/log/emoncms.log");
$log->set_topic("FEEDWRITER");
$log->info("Starting feedwriter process");
// Connect to redis
$redis = new Redis();
while (!$redis->connect("127.0.0.1")) {
    sleep(1);
    $log->warn("Could not connect to redis, retrying");
}
require "Modules/feed/engine/PHPTimeSeries.php";
require "Modules/feed/engine/PHPFina.php";
$engine = array();
$engine[Engine::PHPTIMESERIES] = new PHPTimeSeries($feed_settings['phptimeseries']);
$engine[Engine::PHPFINA] = new PHPFina($feed_settings['phpfina']);
while (true) {
    $len = $redis->llen("feedbuffer");
Example #5
0
function input_controller()
{
    global $mysqli, $redis, $user, $session, $route, $feed_settings;
    // There are no actions in the input module that can be performed with less than write privileges
    if (!$session['write']) {
        return array('content' => false);
    }
    $result = false;
    require_once "Modules/feed/feed_model.php";
    $feed = new Feed($mysqli, $redis, $feed_settings);
    require_once "Modules/input/input_model.php";
    $input = new Input($mysqli, $redis, $feed);
    require_once "Modules/process/process_model.php";
    $process = new Process($mysqli, $input, $feed, $user->get_timezone($session['userid']));
    if ($route->format == 'html') {
        if ($route->action == 'api') {
            $result = view("Modules/input/Views/input_api.php", array());
        } else {
            if ($route->action == 'view') {
                $result = view("Modules/input/Views/input_view.php", array());
            }
        }
    } else {
        if ($route->format == 'json') {
            /*
            
            input/bulk.json?data=[[0,16,1137],[2,17,1437,3164],[4,19,1412,3077]]
            
            The first number of each node is the time offset (see below).
            
            The second number is the node id, this is the unique identifer for the wireless node.
            
            All the numbers after the first two are data values. The first node here (node 16) has only one data value: 1137.
            
            Optional offset and time parameters allow the sender to set the time
            reference for the packets.
            If none is specified, it is assumed that the last packet just arrived.
            The time for the other packets is then calculated accordingly.
            
            offset=-10 means the time of each packet is relative to [now -10 s].
            time=1387730127 means the time of each packet is relative to 1387730127
            (number of seconds since 1970-01-01 00:00:00 UTC)
            
            Examples:
            
            // legacy mode: 4 is 0, 2 is -2 and 0 is -4 seconds to now.
              input/bulk.json?data=[[0,16,1137],[2,17,1437,3164],[4,19,1412,3077]]
            // offset mode: -6 is -16 seconds to now.
              input/bulk.json?data=[[-10,16,1137],[-8,17,1437,3164],[-6,19,1412,3077]]&offset=-10
            // time mode: -6 is 1387730121
              input/bulk.json?data=[[-10,16,1137],[-8,17,1437,3164],[-6,19,1412,3077]]&time=1387730127
            // sentat (sent at) mode:
              input/bulk.json?data=[[520,16,1137],[530,17,1437,3164],[535,19,1412,3077]]&offset=543
            
            See pull request for full discussion:
            https://github.com/emoncms/emoncms/pull/118
            */
            if ($route->action == 'bulk') {
                $valid = true;
                if (!isset($_GET['data']) && isset($_POST['data'])) {
                    $data = json_decode(post('data'));
                } else {
                    $data = json_decode(get('data'));
                }
                $len = count($data);
                if ($len > 0) {
                    if (isset($data[$len - 1][0])) {
                        // Sent at mode: input/bulk.json?data=[[45,16,1137],[50,17,1437,3164],[55,19,1412,3077]]&sentat=60
                        if (isset($_GET['sentat'])) {
                            $time_ref = time() - (int) $_GET['sentat'];
                        } elseif (isset($_POST['sentat'])) {
                            $time_ref = time() - (int) $_POST['sentat'];
                        } elseif (isset($_GET['offset'])) {
                            $time_ref = time() - (int) $_GET['offset'];
                        } elseif (isset($_POST['offset'])) {
                            $time_ref = time() - (int) $_POST['offset'];
                        } elseif (isset($_GET['time'])) {
                            $time_ref = (int) $_GET['time'];
                        } elseif (isset($_POST['time'])) {
                            $time_ref = (int) $_POST['time'];
                        } else {
                            $time_ref = time() - (int) $data[$len - 1][0];
                        }
                        $userid = $session['userid'];
                        $dbinputs = $input->get_inputs($userid);
                        foreach ($data as $item) {
                            if (count($item) > 2) {
                                // check for correct time format
                                $itemtime = (int) $item[0];
                                $time = $time_ref + (int) $itemtime;
                                $nodeid = $item[1];
                                $validate_access = $input->validate_access($dbinputs, $nodeid);
                                if (!$validate_access['success']) {
                                    $valid = false;
                                    $error = $validate_access['message'];
                                    break;
                                }
                                $inputs = array();
                                $name = 1;
                                for ($i = 2; $i < count($item); $i++) {
                                    if (strlen($item[$i])) {
                                        $value = (double) $item[$i];
                                        $inputs[$name] = $value;
                                    }
                                    $name++;
                                }
                                $tmp = array();
                                foreach ($inputs as $name => $value) {
                                    if (!isset($dbinputs[$nodeid][$name])) {
                                        $inputid = $input->create_input($userid, $nodeid, $name);
                                        $dbinputs[$nodeid][$name] = true;
                                        $dbinputs[$nodeid][$name] = array('id' => $inputid, 'processList' => '');
                                        $input->set_timevalue($dbinputs[$nodeid][$name]['id'], $time, $value);
                                    } else {
                                        $input->set_timevalue($dbinputs[$nodeid][$name]['id'], $time, $value);
                                        if ($dbinputs[$nodeid][$name]['processList']) {
                                            $tmp[] = array('value' => $value, 'processList' => $dbinputs[$nodeid][$name]['processList']);
                                        }
                                    }
                                }
                                foreach ($tmp as $i) {
                                    $process->input($time, $i['value'], $i['processList']);
                                }
                            } else {
                                $valid = false;
                                $error = "Format error, bulk item needs at least 3 values";
                            }
                        }
                    } else {
                        $valid = false;
                        $error = "Format error, last item in bulk data does not contain any data";
                    }
                } else {
                    $valid = false;
                    $error = "Format error, json string supplied is not valid";
                }
                if ($valid) {
                    $result = 'ok';
                } else {
                    $result = "Error: {$error}\n";
                    $log = new EmonLogger(__FILE__);
                    $log->error($error);
                }
            } else {
                if ($route->action == 'post') {
                    $valid = true;
                    $error = "";
                    $userid = $session['userid'];
                    $dbinputs = $input->get_inputs($userid);
                    $nodeid = preg_replace('/[^\\p{N}\\p{L}_\\s-.]/u', '', get('node'));
                    $validate_access = $input->validate_access($dbinputs, $nodeid);
                    if (!$validate_access['success']) {
                        $valid = false;
                        $error = $validate_access['message'];
                    } else {
                        if (isset($_GET['time'])) {
                            $time = (int) $_GET['time'];
                        } else {
                            $time = time();
                        }
                        $datain = false;
                        // code below processes input regardless of json or csv type
                        if (isset($_GET['json'])) {
                            $datain = get('json');
                        } else {
                            if (isset($_GET['csv'])) {
                                $datain = get('csv');
                            } else {
                                if (isset($_GET['data'])) {
                                    $datain = get('data');
                                } else {
                                    if (isset($_POST['data'])) {
                                        $datain = post('data');
                                    }
                                }
                            }
                        }
                        if ($datain != "") {
                            $json = preg_replace('/[^\\p{N}\\p{L}_\\s-.:,]/u', '', $datain);
                            $datapairs = explode(',', $json);
                            $data = array();
                            $csvi = 0;
                            for ($i = 0; $i < count($datapairs); $i++) {
                                $keyvalue = explode(':', $datapairs[$i]);
                                if (isset($keyvalue[1])) {
                                    if ($keyvalue[0] == '') {
                                        $valid = false;
                                        $error = "Format error, json key missing or invalid character";
                                    }
                                    if (!is_numeric($keyvalue[1])) {
                                        $valid = false;
                                        $error = "Format error, json value is not numeric";
                                    }
                                    $data[$keyvalue[0]] = (double) $keyvalue[1];
                                } else {
                                    if (!is_numeric($keyvalue[0])) {
                                        $valid = false;
                                        $error = "Format error: csv value is not numeric";
                                    }
                                    $data[$csvi + 1] = (double) $keyvalue[0];
                                    $csvi++;
                                }
                            }
                            $tmp = array();
                            foreach ($data as $name => $value) {
                                if (!isset($dbinputs[$nodeid][$name])) {
                                    $inputid = $input->create_input($userid, $nodeid, $name);
                                    $dbinputs[$nodeid][$name] = true;
                                    $dbinputs[$nodeid][$name] = array('id' => $inputid, 'processList' => '');
                                    $input->set_timevalue($dbinputs[$nodeid][$name]['id'], $time, $value);
                                } else {
                                    $input->set_timevalue($dbinputs[$nodeid][$name]['id'], $time, $value);
                                    if ($dbinputs[$nodeid][$name]['processList']) {
                                        $tmp[] = array('value' => $value, 'processList' => $dbinputs[$nodeid][$name]['processList']);
                                    }
                                }
                            }
                            foreach ($tmp as $i) {
                                $process->input($time, $i['value'], $i['processList']);
                            }
                        } else {
                            $valid = false;
                            $error = "Request contains no data via csv, json or data tag";
                        }
                    }
                    if ($valid) {
                        $result = 'ok';
                    } else {
                        $result = "Error: {$error}\n";
                        $log = new EmonLogger(__FILE__);
                        $log->error($error);
                    }
                } else {
                    if ($route->action == "list") {
                        $result = $input->getlist($session['userid']);
                    } else {
                        if ($route->action == "getinputs") {
                            $result = $input->get_inputs($session['userid']);
                        } else {
                            if ($route->action == "clean") {
                                $result = $input->clean($session['userid']);
                            } else {
                                if (isset($_GET['inputid']) && $input->belongs_to_user($session['userid'], get("inputid"))) {
                                    if ($route->action == 'set') {
                                        $result = $input->set_fields(get('inputid'), get('fields'));
                                    } else {
                                        if ($route->action == "delete") {
                                            $result = $input->delete($session['userid'], get("inputid"));
                                        } else {
                                            if ($route->action == "process") {
                                                if ($route->subaction == "get") {
                                                    $result = $input->get_processlist(get("inputid"));
                                                } else {
                                                    if ($route->subaction == "set") {
                                                        $result = $input->set_processlist(get('inputid'), post('processlist'));
                                                    } else {
                                                        if ($route->subaction == "reset") {
                                                            $result = $input->reset_processlist(get("inputid"));
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return array('content' => $result);
}
$outinterval = 300;
// export interval in seconds
$time = time();
// generate export for last month of this time
$exportpath = './exports';
// where to save export backup file (relative to base emoncms path)
// Dont change bellow this
$fp = fopen("/var/lock/export_daily.lock", "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    echo "Already running\n";
    die;
}
chdir(dirname(__FILE__) . "/../");
require "Lib/EmonLogger.php";
require "process_settings.php";
$log = new EmonLogger(__FILE__);
$log->info("Starting export task script");
$mysqli = @new mysqli($server, $username, $password, $database);
if ($mysqli->connect_error) {
    $log->error("Can't connect to database:" . $mysqli->connect_error);
    die('Check log\\n');
}
if ($redis_enabled) {
    $redis = new Redis();
    if (!$redis->connect($redis_server['host'], $redis_server['port'])) {
        $log->error("Could not connect to redis at " . $redis_server['host'] . ":" . $redis_server['port']);
        die('Check log\\n');
    }
    if (!empty($redis_server['prefix'])) {
        $redis->setOption(Redis::OPT_PREFIX, $redis_server['prefix']);
    }
function wattsup_controller()
{
    global $mysqli, $redis, $user, $session, $route, $feed_settings;
    // First up, a little hack.
    // We need to include an API key with our POST data from the Watts Up?,
    // but the stupid thing limits how long our POST location string can be.
    // SO, we put the API key in the user agent string, cause why not.
    $apikey = $_SERVER["HTTP_USER_AGENT"];
    $session = $user->apikey_session($apikey);
    if (empty($session)) {
        header($_SERVER["SERVER_PROTOCOL"] . " 401 Unauthorized");
        header('WWW-Authenticate: Bearer realm="API KEY", error="invalid_apikey", error_description="Invalid API key"');
        print "Invalid API key";
        $log = new EmonLogger(__FILE__);
        $log->error("Invalid API key '" . $apikey . "'");
        exit;
    }
    // There are no actions in the input module that can be performed with less than write privileges
    if (!$session['write']) {
        return array('content' => false);
    }
    $result = false;
    // Need to get correct files so that we can make inputs
    require_once "Modules/feed/feed_model.php";
    $feed = new Feed($mysqli, $redis, $feed_settings);
    require_once "Modules/input/input_model.php";
    $input = new Input($mysqli, $redis, $feed);
    require_once "Modules/process/process_model.php";
    $process = new Process($mysqli, $input, $feed, $user->get_timezone($session['userid']));
    // Process /wattsup/post.text messages from Watts Up? .net
    if ($route->action == 'post' && $route->format == 'text') {
        // This looks like a correctly configured Watts Up? .net POST
        $valid = true;
        $error = '';
        $userid = $session['userid'];
        $dbinputs = $input->get_inputs($userid);
        // id is set to the Watts Up? device ID
        $nodeid = preg_replace('/[^\\p{N}\\p{L}_\\s-.]/u', '', post('id'));
        // Make sure we can do this. Copied from input_controller.php
        $validate_access = $input->validate_access($dbinputs, $nodeid);
        if (!$validate_access['success']) {
            $valid = false;
            $error = $validate_access['message'];
        } else {
            // Insert this record into the emoncms format
            $time = time();
            // Array to store the relevant fields in
            $data = array();
            $watts = post('w');
            $volts = post('v');
            $amps = post('a');
            $watth = post('wh');
            $maxwatts = post('wmx');
            $maxvolts = post('vmx');
            $maxamps = post('amx');
            $minwatts = post('wmi');
            $minvolts = post('vmi');
            $minamps = post('ami');
            $pf = post('pf');
            $pcy = post('pcy');
            $freq = post('frq');
            $voltamps = post('va');
            # Only include fields we actually got
            if (is_numeric($watts)) {
                $data['watts'] = $watts / 10;
            }
            if (is_numeric($volts)) {
                $data['volts'] = $volts / 10;
            }
            if (is_numeric($amps)) {
                $data['amps'] = $amps / 1000;
            }
            if (is_numeric($watth)) {
                $data['watt_hours'] = $watth / 1000;
            }
            if (is_numeric($maxwatts)) {
                $data['max_watts'] = $maxwatts / 10;
            }
            if (is_numeric($maxvolts)) {
                $data['max_volts'] = $maxvolts / 10;
            }
            if (is_numeric($maxamps)) {
                $data['max_amps'] = $maxamps / 1000;
            }
            if (is_numeric($minwatts)) {
                $data['min_watts'] = $minwatts / 10;
            }
            if (is_numeric($minvolts)) {
                $data['min_volts'] = $minvolts / 10;
            }
            if (is_numeric($minamps)) {
                $data['min_amps'] = $minamps / 1000;
            }
            if (is_numeric($pf)) {
                $data['power_factor'] = $pf;
            }
            if (is_numeric($pcy)) {
                $data['power_cycle'] = $pcy;
            }
            if (is_numeric($freq)) {
                $data['freq'] = $freq / 10;
            }
            if (is_numeric($voltamps)) {
                $data['volt_amps'] = $voltamps / 10;
            }
            // Iterate all new data items to insert
            $tmp = array();
            foreach ($data as $name => $value) {
                // Check if this is an existing field in this node or not
                if (!isset($dbinputs[$nodeid][$name])) {
                    // New field.
                    $inputid = $input->create_input($userid, $nodeid, $name);
                    $dbinputs[$nodeid][$name] = true;
                    $dbinputs[$nodeid][$name] = array('id' => $inputid, 'processList' => '');
                    $input->set_timevalue($dbinputs[$nodeid][$name]['id'], $time, $value);
                } else {
                    // Existing field, just insert
                    $input->set_timevalue($dbinputs[$nodeid][$name]['id'], $time, $value);
                    // If there are processes listening to this field, we need
                    // to pass the data to those as well
                    if ($dbinputs[$nodeid][$name]['processList']) {
                        $tmp[] = array('value' => $value, 'processList' => $dbinputs[$nodeid][$name]['processList'], 'opt' => array('sourcetype' => "WATTSUP", 'sourceid' => $dbinputs[$nodeid][$name]['id']));
                    }
                }
            }
            // Actually insert all of the data to the process
            foreach ($tmp as $i) {
                $process->input($time, $i['value'], $i['processList'], $i['opt']);
            }
        }
        if ($valid) {
            $result = 'ok';
        } else {
            $result = "Error: {$error}\n";
        }
    }
    return array('content' => $result);
}
Part of the OpenEnergyMonitor project: http://openenergymonitor.org
*/
define('EMONCMS_EXEC', 1);
$fp = fopen("/var/lock/input_queue_processor.lock", "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    echo "Already running\n";
    die;
}
chdir(dirname(__FILE__) . "/../");
require "Lib/EmonLogger.php";
require "process_settings.php";
if (!$redis_enabled) {
    echo "Error: setting must be true: redis_enabled\n";
    die;
}
$log = new EmonLogger(__FILE__);
$log->info("Starting REDIS Input Queue Processor script");
$mysqli = @new mysqli($server, $username, $password, $database, $port);
if ($mysqli->connect_error) {
    $log->error("Can't connect to database:" . $mysqli->connect_error);
    die('Check log\\n');
}
if ($redis_enabled) {
    $redis = new Redis();
    if (!$redis->connect($redis_server['host'], $redis_server['port'])) {
        $log->error("Could not connect to redis at " . $redis_server['host'] . ":" . $redis_server['port']);
        die('Check log\\n');
    }
    if (!empty($redis_server['prefix'])) {
        $redis->setOption(Redis::OPT_PREFIX, $redis_server['prefix']);
    }
Example #9
0
Emoncms then processes these inputs in the same way as they would be
    if sent to the HTTP Api.
*/
// This code is released under the GNU Affero General Public License.
// OpenEnergyMonitor project:
// http://openenergymonitor.org
define('EMONCMS_EXEC', 1);
$fp = fopen("/var/lock/phpmqtt_input.lock", "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    echo "Already running\n";
    die;
}
chdir(dirname(__FILE__) . "/../");
require "Lib/EmonLogger.php";
require "process_settings.php";
$log = new EmonLogger(__FILE__);
$log->warn("Starting MQTT Input script");
if (!$mqtt_enabled) {
    echo "Error MQTT input script: MQTT must be enabled in settings.php\n";
    $log->error("MQTT must be enabled in settings.php");
    die;
}
$mysqli = @new mysqli($server, $username, $password, $database);
if ($mysqli->connect_error) {
    $log->error("Cannot connect to MYSQL database:" . $mysqli->connect_error);
    die('Check log\\n');
}
if ($redis_enabled) {
    $redis = new Redis();
    if (!$redis->connect($redis_server['host'], $redis_server['port'])) {
        $log->error("Cannot connect to redis at " . $redis_server['host'] . ":" . $redis_server['port']);
Example #10
0
// This code is released under the GNU Affero General Public License.
// OpenEnergyMonitor project:
// http://openenergymonitor.org
$emoncms_config_file = "/home/pi/data/emoncms.conf";
$emonhub_config_file = "/home/pi/data/emonhub.conf";
$topic = "emonhub/rx/#";
define('EMONCMS_EXEC', 1);
$fp = fopen("/home/pi/data/nodes_mqtt_process_lock", "w");
if (!flock($fp, LOCK_EX | LOCK_NB)) {
    echo "Already running\n";
    die;
}
chdir("/var/www/emoncms");
// Emoncms logger
require "Modules/log/EmonLogger.php";
$log = new EmonLogger(__FILE__);
$log->set_logfile("/var/log/emoncms.log");
$log->set_topic("MQTT");
$log->info("Starting emoncms mqtt nodes process");
require "Modules/nodes/ConfObj.php";
require "process_settings.php";
// Connect to mysql
$mysqli = @new mysqli($server, $username, $password, $database);
while ($mysqli->connect_error) {
    sleep(1);
    $log->warn("Could not connect to mysql, retrying");
    $mysqli = @new mysqli($server, $username, $password, $database);
}
// Connect to redis
$redis = new Redis();
while (!$redis->connect("127.0.0.1")) {
function db_schema_setup($mysqli, $schema, $apply)
{
    $log = new EmonLogger(__FILE__);
    $operations = array();
    while ($table = key($schema)) {
        $log->info($table);
        error_log($table);
        // if table exists:
        $result = $mysqli->query("SHOW TABLES LIKE '" . $table . "'");
        if ($result != null && $result->num_rows == 1) {
            // $out[] = array('Table',$table,"ok");
            //-----------------------------------------------------
            // Check table fields from schema
            //-----------------------------------------------------
            while ($field = key($schema[$table])) {
                $type = $schema[$table][$field]['type'];
                if (isset($schema[$table][$field]['Null'])) {
                    $null = $schema[$table][$field]['Null'];
                } else {
                    $null = "YES";
                }
                if (isset($schema[$table][$field]['Key'])) {
                    $key = $schema[$table][$field]['Key'];
                } else {
                    $key = null;
                }
                if (isset($schema[$table][$field]['default'])) {
                    $default = $schema[$table][$field]['default'];
                } else {
                    unset($default);
                }
                if (isset($schema[$table][$field]['Extra'])) {
                    $extra = $schema[$table][$field]['Extra'];
                } else {
                    $extra = null;
                }
                // if field exists:
                $result = $mysqli->query("SHOW COLUMNS FROM `{$table}` LIKE '{$field}'");
                if ($result->num_rows == 0) {
                    $query = "ALTER TABLE `{$table}` ADD `{$field}` {$type}";
                    if ($null) {
                        $query .= " NOT NULL";
                    }
                    if (isset($default)) {
                        $query .= " DEFAULT '{$default}'";
                    }
                    $operations[] = $query;
                    if ($apply) {
                        $mysqli->query($query);
                    }
                } else {
                    $result = $mysqli->query("DESCRIBE {$table} `{$field}`");
                    $array = $result->fetch_array();
                    $query = "";
                    if ($array['Type'] != $type) {
                        $query .= ";";
                    }
                    if (isset($default) && $array['Default'] != $default) {
                        $query .= " Default '{$default}'";
                    }
                    if ($array['Null'] != $null && $null == "NO") {
                        $query .= " not null";
                    }
                    if ($array['Extra'] != $extra && $extra == "auto_increment") {
                        $query .= " auto_increment";
                    }
                    if ($array['Key'] != $key && $key == "PRI") {
                        $query .= " primary key";
                    }
                    if ($query) {
                        $query = "ALTER TABLE {$table} MODIFY `{$field}` {$type}" . $query;
                    }
                    if ($query) {
                        $operations[] = $query;
                    }
                    if ($query && $apply) {
                        $mysqli->query($query);
                    }
                }
                next($schema[$table]);
            }
        } else {
            //-----------------------------------------------------
            // Create table from schema
            //-----------------------------------------------------
            $query = "CREATE TABLE " . $table . " (";
            while ($field = key($schema[$table])) {
                $type = $schema[$table][$field]['type'];
                if (isset($schema[$table][$field]['Null'])) {
                    $null = $schema[$table][$field]['Null'];
                } else {
                    $null = "YES";
                }
                if (isset($schema[$table][$field]['Key'])) {
                    $key = $schema[$table][$field]['Key'];
                } else {
                    $key = null;
                }
                if (isset($schema[$table][$field]['default'])) {
                    $default = $schema[$table][$field]['default'];
                } else {
                    $default = null;
                }
                if (isset($schema[$table][$field]['Extra'])) {
                    $extra = $schema[$table][$field]['Extra'];
                } else {
                    $extra = null;
                }
                $query .= '`' . $field . '`';
                $query .= " {$type}";
                if ($default) {
                    $query .= " Default '{$default}'";
                }
                if ($null == "NO") {
                    $query .= " not null";
                }
                if ($extra) {
                    $query .= " auto_increment";
                }
                if ($key) {
                    $query .= " primary key";
                }
                next($schema[$table]);
                if (key($schema[$table])) {
                    $query .= ", ";
                }
            }
            $query .= ")";
            $query .= " ENGINE=MYISAM";
            if ($query) {
                $operations[] = $query;
            }
            if ($query && $apply) {
                $mysqli->query($query);
            }
        }
        next($schema);
    }
    return $operations;
}