Przeglądaj źródła

Sidebar Updates

Benjamin Harris 2 miesięcy temu
rodzic
commit
c1030aa24c

+ 92 - 115
api/Rest.inc.php

@@ -1,118 +1,95 @@
 <?php
-    /* File : Rest.inc.php
-    */
-    class REST {
-         
-        public $_allow = array();
-        public $_content_type = "application/json";
-        public $_request = array();
-         
-        private $_method = "";      
-        private $_code = 200;
-         
-        public function __construct(){
-            $this->inputs();
+/**
+ * api/Rest.inc.php
+ *
+ * Base REST class. Fixed for PHP 8 compatibility:
+ * - Removed get_magic_quotes_gpc() which was removed in PHP 8.0
+ * - cleanInputs() no longer calls stripslashes conditionally
+ */
+class REST
+{
+    public array  $_allow        = [];
+    public string $_content_type = 'application/json';
+    public array  $_request      = [];
+
+    private string $_method = '';
+    private int    $_code   = 200;
+
+    public function __construct()
+    {
+        $this->inputs();
+    }
+
+    public function get_referer(): string
+    {
+        return $_SERVER['HTTP_REFERER'] ?? '';
+    }
+
+    public function response(string $data, int $status): void
+    {
+        $this->_code = $status;
+        $this->set_headers();
+        echo $data;
+        exit;
+    }
+
+    private function get_status_message(): string
+    {
+        $status = [
+            100 => 'Continue',
+            200 => 'OK',
+            201 => 'Created',
+            204 => 'No Content',
+            301 => 'Moved Permanently',
+            302 => 'Found',
+            400 => 'Bad Request',
+            401 => 'Unauthorized',
+            403 => 'Forbidden',
+            404 => 'Not Found',
+            405 => 'Method Not Allowed',
+            406 => 'Not Acceptable',
+            409 => 'Conflict',
+            500 => 'Internal Server Error',
+        ];
+        return $status[$this->_code] ?? 'Internal Server Error';
+    }
+
+    public function get_request_method(): string
+    {
+        return $_SERVER['REQUEST_METHOD'];
+    }
+
+    private function inputs(): void
+    {
+        switch ($this->get_request_method()) {
+            case 'POST':
+                $this->_request = $this->cleanInputs($_POST);
+                break;
+            case 'GET':
+            case 'DELETE':
+                $this->_request = $this->cleanInputs($_GET);
+                break;
+            case 'PUT':
+                parse_str(file_get_contents('php://input'), $input);
+                $this->_request = $this->cleanInputs($input);
+                break;
+            default:
+                $this->response('', 406);
         }
-         
-        public function get_referer(){
-            return $_SERVER['HTTP_REFERER'];
+    }
+
+    private function cleanInputs(array|string $data): array|string
+    {
+        if (is_array($data)) {
+            return array_map([$this, 'cleanInputs'], $data);
         }
-         
-        public function response($data,$status){
-            $this->_code = ($status)?$status:200;
-            $this->set_headers();
-            echo $data;
-            exit;
-        }
-         
-        private function get_status_message(){
-            $status = array(
-                        100 => 'Continue',  
-                        101 => 'Switching Protocols',  
-                        200 => 'OK',
-                        201 => 'Created',  
-                        202 => 'Accepted',  
-                        203 => 'Non-Authoritative Information',  
-                        204 => 'No Content',  
-                        205 => 'Reset Content',  
-                        206 => 'Partial Content',  
-                        300 => 'Multiple Choices',  
-                        301 => 'Moved Permanently',  
-                        302 => 'Found',  
-                        303 => 'See Other',  
-                        304 => 'Not Modified',  
-                        305 => 'Use Proxy',  
-                        306 => '(Unused)',  
-                        307 => 'Temporary Redirect',  
-                        400 => 'Bad Request',  
-                        401 => 'Unauthorized',  
-                        402 => 'Payment Required',  
-                        403 => 'Forbidden',  
-                        404 => 'Not Found',  
-                        405 => 'Method Not Allowed',  
-                        406 => 'Not Acceptable',  
-                        407 => 'Proxy Authentication Required',  
-                        408 => 'Request Timeout',  
-                        409 => 'Conflict',  
-                        410 => 'Gone',  
-                        411 => 'Length Required',  
-                        412 => 'Precondition Failed',  
-                        413 => 'Request Entity Too Large',  
-                        414 => 'Request-URI Too Long',  
-                        415 => 'Unsupported Media Type',  
-                        416 => 'Requested Range Not Satisfiable',  
-                        417 => 'Expectation Failed',  
-                        500 => 'Internal Server Error',  
-                        501 => 'Not Implemented',  
-                        502 => 'Bad Gateway',  
-                        503 => 'Service Unavailable',  
-                        504 => 'Gateway Timeout',  
-                        505 => 'HTTP Version Not Supported');
-            return ($status[$this->_code])?$status[$this->_code]:$status[500];
-        }
-         
-        public function get_request_method(){
-            return $_SERVER['REQUEST_METHOD'];
-        }
-         
-        private function inputs(){
-            switch($this->get_request_method()){
-                case "POST":
-                    $this->_request = $this->cleanInputs($_POST);
-                    break;
-                case "GET":
-                case "DELETE":
-                    $this->_request = $this->cleanInputs($_GET);
-                    break;
-                case "PUT":
-                    parse_str(file_get_contents("php://input"),$this->_request);
-                    $this->_request = $this->cleanInputs($this->_request);
-                    break;
-                default:
-                    $this->response('',406);
-                    break;
-            }
-        }       
-         
-        private function cleanInputs($data){
-            $clean_input = array();
-            if(is_array($data)){
-                foreach($data as $k => $v){
-                    $clean_input[$k] = $this->cleanInputs($v);
-                }
-            }else{
-                if(get_magic_quotes_gpc()){
-                    $data = trim(stripslashes($data));
-                }
-                $data = strip_tags($data);
-                $clean_input = trim($data);
-            }
-            return $clean_input;
-        }       
-         
-        private function set_headers(){
-            header("HTTP/1.1 ".$this->_code." ".$this->get_status_message());
-            header("Content-Type:".$this->_content_type);
-        }
-    }   
-?>
+        // PHP 8: magic_quotes were removed; just strip tags and trim
+        return trim(strip_tags((string) $data));
+    }
+
+    private function set_headers(): void
+    {
+        header('HTTP/1.1 ' . $this->_code . ' ' . $this->get_status_message());
+        header('Content-Type: ' . $this->_content_type);
+    }
+}

+ 45 - 65
api/api.php

@@ -1,71 +1,51 @@
 <?php
-     
-require_once("Rest.inc.php");
-     
-class API extends REST {
-     
-    public $data = "";
-    //Enter details of your database
-    const DB_SERVER = "localhost";
-    const DB_USER = "root";
-    const DB_PASSWORD = "R3M0T31";
-    const DB = "cropmonitor";
-     
-    private $db = NULL;
- 
-    public function __construct(){
-        parent::__construct();              // Init parent contructor
-        $this->dbConnect();                 // Initiate Database connection
-}
-     
-private function dbConnect(){
-        $this->db = mysql_connect(self::DB_SERVER,self::DB_USER,self::DB_PASSWORD);
-        if($this->db)
-            mysql_select_db(self::DB,$this->db);
-}
-     
-    /*
-     * Public method for access api.
-     * This method dynmically call the method based on the query string
-     *
-     */
-public function processApi(){
-        $func = strtolower(trim(str_replace("/","",$_REQUEST['rquest'])));
-        if((int)method_exists($this,$func) > 0)
+/**
+ * api/api.php
+ *
+ * Minimal REST API stub — migrated from the legacy mysql_connect version.
+ * The original used mysql_connect() which was removed in PHP 7.
+ * Rewritten to use PDO via config/database.php.
+ *
+ * Note: this API has no real endpoints yet. Extend as needed.
+ */
+
+require_once __DIR__ . '/../config/database.php';
+require_once __DIR__ . '/Rest.inc.php';
+
+class API extends REST
+{
+    public string $data = '';
+
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    public function processApi(): void
+    {
+        $func = strtolower(trim(str_replace('/', '', $this->_request['rquest'] ?? '')));
+        if ($func !== '' && method_exists($this, $func)) {
             $this->$func();
-        else
-            $this->response('Error code 404, Page not found',404);   // If the method not exist with in this class, response would be "Page not found".
-}
-private function hello(){
-    echo str_replace("this","that","HELLO WORLD!!");
- 
-}
-     
- 
-private function test(){    
-    // Cross validation if the request method is GET else it will return "Not Acceptable" status
-    if($this->get_request_method() != "GET"){
-        $this->response('',406);
+        } else {
+            $this->response('{"error":"Not found"}', 404);
+        }
     }
-    $myDatabase= $this->db;// variable to access your database
-    $param=$this->_request['var'];
-    // If success everythig is good send header as "OK" return param
-    $this->response($param, 200);    
-}
- 
-     
-    /*
-     *  Encode array into JSON
-    */
-    private function json($data){
-        if(is_array($data)){
-            return json_encode($data);
+
+    private function hello(): void
+    {
+        $this->response(json_encode(['message' => 'Hello from Crop Monitor API']), 200);
+    }
+
+    private function test(): void
+    {
+        if ($this->get_request_method() !== 'GET') {
+            $this->response('', 406);
+            return;
         }
+        $param = $this->_request['var'] ?? '';
+        $this->response(json_encode(['param' => $param]), 200);
     }
 }
- 
-    // Initiiate Library
-     
-    $api = new API;
-    $api->processApi();
-?>
+
+$api = new API();
+$api->processApi();

+ 187 - 146
api/updateweatherstation.php

@@ -1,151 +1,192 @@
 <?php
-$sql = null;
-
-$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-
-$action=(isset($_GET["action"])) ? $_GET["action"] : "";
-$ID=(isset($_GET["ID"])) ? $_GET["ID"] : "";
-$PASSWORD=(isset($_GET["PASSWORD"])) ? $_GET["PASSWORD"] : "";
-$dateutc=(isset($_GET["dateutc"])) ? $_GET["dateutc"] : "";
-$winddir=(isset($_GET["winddir"])) ? $_GET["winddir"] : "";
-$windspeedmph=(isset($_GET["windspeedmph"])) ? $_GET["windspeedmph"] : "";
-$windgustmph=(isset($_GET["windgustmph"])) ? $_GET["windgustmph"] : "";
-$windgustdir=(isset($_GET["windgustdir"])) ? $_GET["windgustdir"] : "";
-$windspdmph_avg2m=(isset($_GET["windspdmph_avg2m"])) ? $_GET["windspdmph_avg2m"] : "";
-$winddir_avg2m=(isset($_GET["winddir_avg2m"])) ? $_GET["winddir_avg2m"] : "";
-$windgustmph_10m=(isset($_GET["windgustmph_10m"])) ? $_GET["windgustmph_10m"] : "";
-$windgustdir_10m=(isset($_GET["windgustdir_10m"])) ? $_GET["windgustdir_10m"] : "";
-$humidity=(isset($_GET["humidity"])) ? $_GET["humidity"] : "";
-$dewptf=(isset($_GET["dewptf"])) ? $_GET["dewptf"] : "";
-$tempf=(isset($_GET["tempf"])) ? $_GET["tempf"] : "";
-$temp2f=(isset($_GET["temp2f"])) ? $_GET["temp2f"] : "";
-$temp3f=(isset($_GET["temp3f"])) ? $_GET["temp3f"] : "";
-$temp4f=(isset($_GET["temp4f"])) ? $_GET["temp4f"] : "";
-$rainin=(isset($_GET["rainin"])) ? $_GET["rainin"] : "";
-$dailyrainin=(isset($_GET["dailyrainin"])) ? $_GET["dailyrainin"] : "";
-$baromin=(isset($_GET["baromin"])) ? $_GET["baromin"] : "";
-$weather=(isset($_GET["weather"])) ? $_GET["weather"] : "";
-$clouds=(isset($_GET["clouds"])) ? $_GET["clouds"] : "";
-$soiltempf=(isset($_GET["soiltempf"])) ? $_GET["soiltempf"] : "";
-$soiltemp2f=(isset($_GET["soiltemp2f"])) ? $_GET["soiltemp2f"] : "";
-$soiltemp3f=(isset($_GET["soiltemp3f"])) ? $_GET["soiltemp3f"] : "";
-$soiltemp4f=(isset($_GET["soiltemp4f"])) ? $_GET["soiltemp4f"] : "";
-$soilmoisture=(isset($_GET["soilmoisture"])) ? $_GET["soilmoisture"] : "";
-$soilmoisture2=(isset($_GET["soilmoisture2"])) ? $_GET["soilmoisture2"] : "";
-$soilmoisture3=(isset($_GET["soilmoisture3"])) ? $_GET["soilmoisture3"] : "";
-$soilmoisture4=(isset($_GET["soilmoisture4"])) ? $_GET["soilmoisture4"] : "";
-$leafwetness=(isset($_GET["leafwetness"])) ? $_GET["leafwetness"] : "";
-$leafwetness2=(isset($_GET["leafwetness2"])) ? $_GET["leafwetness2"] : "";
-$solarradiation=(isset($_GET["solarradiation"])) ? $_GET["solarradiation"] : "";
-$UV=(isset($_GET["UV"])) ? $_GET["UV"] : "";
-$visibility=(isset($_GET["visibility"])) ? $_GET["visibility"] : "";
-$indoortempf=(isset($_GET["indoortempf"])) ? $_GET["indoortempf"] : "";
-$indoorhumidity=(isset($_GET["indoorhumidity"])) ? $_GET["indoorhumidity"] : "";
-
-//add current datetime if not given.
-if ($dateutc === "now"){
-    $dateutc = gmdate("Y-m-d\TH%3Ai%3As\Z");
-} else {
-    $dateutc;
+/**
+ * api/updateweatherstation.php
+ *
+ * Weather station data ingestion endpoint.
+ * Authenticates the station using ID + PASSWORD against client_records,
+ * then inserts a row into weather_station using PDO prepared statements.
+ *
+ * Expected GET params (Weather Underground protocol):
+ *   ID, PASSWORD, dateutc, winddir, windspeedmph, humidity, tempf, ...
+ */
+
+require_once __DIR__ . '/../config/database.php';
+
+header('Content-Type: text/plain');
+
+// ---------------------------------------------------------------------------
+// Authenticate station: ID + PASSWORD must match client_records.wustationid
+// and client_records.wuapikey for the calling station.
+// ---------------------------------------------------------------------------
+$stationId = trim($_GET['ID']       ?? '');
+$password  = trim($_GET['PASSWORD'] ?? '');
+
+if ($stationId === '' || $password === '') {
+    http_response_code(401);
+    echo 'error: missing credentials';
+    exit;
 }
 
-// Check connection
-	if (mysqli_connect_errno())
-		{
-		echo "Failed to connect to MySQL: " . mysqli_connect_error();
-		}
-		
-		
-$sql = mysqli_query($con, "INSERT INTO `weather_station`
-        (
-        action,
-        ID,
-        PASSWORD,
-        dateutc,
-        winddir,
-        windspeedmph,
-        windgustmph,
-        windgustdir,
-        windspdmph_avg2m,
-        winddir_avg2m,
-        windgustmph_10m,
-        windgustdir_10m,
-        humidity,
-        dewptf,
-        tempf,
-        temp2f,
-        temp3f,
-        temp4f,
-        rainin,
-        dailyrainin,
-        baromin,
-        weather,
-        clouds,
-        soiltempf,
-        soiltemp2f,
-        soiltemp3f,
-        soiltemp4f,
-        soilmoisture,
-        soilmoisture2,
-        soilmoisture3,
-        soilmoisture4,
-        leafwetness,
-        leafwetness2,
-        solarradiation,
-        UV,
-        visibility,
-        indoortempf,
-        indoorhumidity
-        ) 
-            VALUES
-        (
-        '" . $action . "',
-        '" . $ID . "',
-        '" . $PASSWORD . "',
-        '" . $dateutc . "',
-        '" . $winddir . "',
-        '" . $windspeedmph . "',
-        '" . $windgustmph . "',
-        '" . $windgustdir . "',
-        '" . $windspdmph_avg2m . "',
-        '" . $winddir_avg2m . "',
-        '" . $windgustmph_10m . "',
-        '" . $windgustdir_10m . "',
-        '" . $humidity . "',
-        '" . $dewptf . "',
-        '" . $tempf . "',
-        '" . $temp2f . "',
-        '" . $temp3f . "',
-        '" . $temp4f . "',
-        '" . $rainin . "',
-        '" . $dailyrainin . "',
-        '" . $baromin . "',
-        '" . $weather . "',
-        '" . $clouds . "',
-        '" . $soiltempf . "',
-        '" . $soiltemp2f . "',
-        '" . $soiltemp3f . "',
-        '" . $soiltemp4f . "',
-        '" . $soilmoisture . "',
-        '" . $soilmoisture2 . "',
-        '" . $soilmoisture3 . "',
-        '" . $soilmoisture4 . "',
-        '" . $leafwetness . "',
-        '" . $leafwetness2 . "',
-        '" . $solarradiation . "',
-        '" . $UV . "',
-        '" . $visibility . "',
-        '" . $indoortempf . "',
-        '" . $indoorhumidity . "'
-        )
-        ");
-
-if ($sql === TRUE)
-	{
-	echo "success"; //CHECKING
-    } else {
-    die(mysqli_error($con)); // TODO: better error handling
-    //echo "User Profile incorrect";
+try {
+    $pdo = getDBConnection();
+
+    $stmt = $pdo->prepare(
+        'SELECT id FROM client_records WHERE wustationid = ? AND wuapikey = ? LIMIT 1'
+    );
+    $stmt->execute([$stationId, $password]);
+
+    if (!$stmt->fetch()) {
+        http_response_code(401);
+        echo 'error: invalid station credentials';
+        exit;
+    }
+} catch (PDOException $e) {
+    error_log('updateweatherstation auth error: ' . $e->getMessage());
+    http_response_code(500);
+    echo 'error: server error';
+    exit;
 }
 
-mysqli_close($con);
+// ---------------------------------------------------------------------------
+// Parse and sanitise all numeric / string fields
+// ---------------------------------------------------------------------------
+
+/** Cast a GET param to float, returning null if missing or non-numeric. */
+function getFloat(string $key): ?float
+{
+    $v = $_GET[$key] ?? null;
+    if ($v === null || $v === '') return null;
+    return is_numeric($v) ? (float) $v : null;
+}
+
+/** Cast a GET param to int, returning null if missing or non-numeric. */
+function getInt(string $key): ?int
+{
+    $v = $_GET[$key] ?? null;
+    if ($v === null || $v === '') return null;
+    return is_numeric($v) ? (int) $v : null;
+}
+
+$action = trim($_GET['action'] ?? '');
+$action = substr($action, 0, 50); // max 50 chars
+
+$dateutc = trim($_GET['dateutc'] ?? '');
+if ($dateutc === 'now' || $dateutc === '') {
+    $dateutc = gmdate('Y-m-d H:i:s');
+} else {
+    // Validate / normalise datetime; reject anything that doesn't parse
+    $ts = strtotime($dateutc);
+    $dateutc = $ts !== false ? gmdate('Y-m-d H:i:s', $ts) : gmdate('Y-m-d H:i:s');
+}
+
+// Numeric sensor readings
+$winddir          = getFloat('winddir');
+$windspeedmph     = getFloat('windspeedmph');
+$windgustmph      = getFloat('windgustmph');
+$windgustdir      = getFloat('windgustdir');
+$windspdmph_avg2m = getFloat('windspdmph_avg2m');
+$winddir_avg2m    = getFloat('winddir_avg2m');
+$windgustmph_10m  = getFloat('windgustmph_10m');
+$windgustdir_10m  = getFloat('windgustdir_10m');
+$humidity         = getFloat('humidity');
+$dewptf           = getFloat('dewptf');
+$tempf            = getFloat('tempf');
+$temp2f           = getFloat('temp2f');
+$temp3f           = getFloat('temp3f');
+$temp4f           = getFloat('temp4f');
+$rainin           = getFloat('rainin');
+$dailyrainin      = getFloat('dailyrainin');
+$baromin          = getFloat('baromin');
+$soiltempf        = getFloat('soiltempf');
+$soiltemp2f       = getFloat('soiltemp2f');
+$soiltemp3f       = getFloat('soiltemp3f');
+$soiltemp4f       = getFloat('soiltemp4f');
+$soilmoisture     = getFloat('soilmoisture');
+$soilmoisture2    = getFloat('soilmoisture2');
+$soilmoisture3    = getFloat('soilmoisture3');
+$soilmoisture4    = getFloat('soilmoisture4');
+$leafwetness      = getFloat('leafwetness');
+$leafwetness2     = getFloat('leafwetness2');
+$solarradiation   = getFloat('solarradiation');
+$UV               = getFloat('UV');
+$visibility       = getFloat('visibility');
+$indoortempf      = getFloat('indoortempf');
+$indoorhumidity   = getFloat('indoorhumidity');
+
+// Short string fields
+$weather = substr(trim($_GET['weather'] ?? ''), 0, 100);
+$clouds  = substr(trim($_GET['clouds']  ?? ''), 0, 100);
+
+// ---------------------------------------------------------------------------
+// Insert
+// ---------------------------------------------------------------------------
+try {
+    $stmt = $pdo->prepare('
+        INSERT INTO `weather_station`
+            (action, ID, dateutc,
+             winddir, windspeedmph, windgustmph, windgustdir,
+             windspdmph_avg2m, winddir_avg2m, windgustmph_10m, windgustdir_10m,
+             humidity, dewptf, tempf, temp2f, temp3f, temp4f,
+             rainin, dailyrainin, baromin, weather, clouds,
+             soiltempf, soiltemp2f, soiltemp3f, soiltemp4f,
+             soilmoisture, soilmoisture2, soilmoisture3, soilmoisture4,
+             leafwetness, leafwetness2, solarradiation, UV, visibility,
+             indoortempf, indoorhumidity)
+        VALUES
+            (:action, :ID, :dateutc,
+             :winddir, :windspeedmph, :windgustmph, :windgustdir,
+             :windspdmph_avg2m, :winddir_avg2m, :windgustmph_10m, :windgustdir_10m,
+             :humidity, :dewptf, :tempf, :temp2f, :temp3f, :temp4f,
+             :rainin, :dailyrainin, :baromin, :weather, :clouds,
+             :soiltempf, :soiltemp2f, :soiltemp3f, :soiltemp4f,
+             :soilmoisture, :soilmoisture2, :soilmoisture3, :soilmoisture4,
+             :leafwetness, :leafwetness2, :solarradiation, :UV, :visibility,
+             :indoortempf, :indoorhumidity)
+    ');
+
+    $stmt->execute([
+        ':action'          => $action,
+        ':ID'              => $stationId,
+        ':dateutc'         => $dateutc,
+        ':winddir'         => $winddir,
+        ':windspeedmph'    => $windspeedmph,
+        ':windgustmph'     => $windgustmph,
+        ':windgustdir'     => $windgustdir,
+        ':windspdmph_avg2m'=> $windspdmph_avg2m,
+        ':winddir_avg2m'   => $winddir_avg2m,
+        ':windgustmph_10m' => $windgustmph_10m,
+        ':windgustdir_10m' => $windgustdir_10m,
+        ':humidity'        => $humidity,
+        ':dewptf'          => $dewptf,
+        ':tempf'           => $tempf,
+        ':temp2f'          => $temp2f,
+        ':temp3f'          => $temp3f,
+        ':temp4f'          => $temp4f,
+        ':rainin'          => $rainin,
+        ':dailyrainin'     => $dailyrainin,
+        ':baromin'         => $baromin,
+        ':weather'         => $weather,
+        ':clouds'          => $clouds,
+        ':soiltempf'       => $soiltempf,
+        ':soiltemp2f'      => $soiltemp2f,
+        ':soiltemp3f'      => $soiltemp3f,
+        ':soiltemp4f'      => $soiltemp4f,
+        ':soilmoisture'    => $soilmoisture,
+        ':soilmoisture2'   => $soilmoisture2,
+        ':soilmoisture3'   => $soilmoisture3,
+        ':soilmoisture4'   => $soilmoisture4,
+        ':leafwetness'     => $leafwetness,
+        ':leafwetness2'    => $leafwetness2,
+        ':solarradiation'  => $solarradiation,
+        ':UV'              => $UV,
+        ':visibility'      => $visibility,
+        ':indoortempf'     => $indoortempf,
+        ':indoorhumidity'  => $indoorhumidity,
+    ]);
+
+    echo 'success';
+} catch (PDOException $e) {
+    error_log('updateweatherstation insert error: ' . $e->getMessage());
+    http_response_code(500);
+    echo 'error: server error';
+}

+ 82 - 74
client-assets/table/gettable.php

@@ -1,84 +1,92 @@
 <?php
+/**
+ * client-assets/table/gettable.php
+ *
+ * AJAX DataTable endpoint. Requires authentication and a whitelisted table name.
+ */
 
-define('DB_HOST', 'localhost');
-       define('DB_USER', 'root');
-       define('DB_PASSWORD', 'R3M0T31');
-       define('DB_DATABASE', 'cropmonitor');
+require_once __DIR__ . '/../../config/database.php';
+require_once __DIR__ . '/../../lib/auth.php';
 
-//Connect to mysql server
-$link = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD);
-if(!$link) {
-       die('Failed to connect to server: ' . mysqli_error());
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
 }
 
-//Select database
-$db = mysqli_select_db($link, DB_DATABASE);
-if(!$db) {
-       die("Unable to select database");
+if (!isLoggedIn()) {
+    http_response_code(401);
+    echo json_encode(['error' => 'Unauthorised']);
+    exit;
 }
 
-$query = "SHOW TABLES;";
-$result_tables = mysqli_query($link, $query);
-
-if (!isset($_REQUEST["table"])){
-	die ("no table selected");
-}
-
-$num_rows = (isset($_REQUEST["num_rows"])) ? intval($_REQUEST["num_rows"]) : 30;
-$page = (isset($_REQUEST["page"])) ? intval($_REQUEST["page"]) : 0;
-
-
-$query_fields = "SHOW COLUMNS FROM ".$_REQUEST["table"];
-$results_fields = mysqli_query($link, $query_fields);
-
-$r_fields = array();
-while ($row = mysqli_fetch_assoc($results_fields)){
-	$r_fields[] = $row["Field"];
-}
-
-
-$query = "SELECT * FROM ".$_REQUEST["table"];
-if (isset($_REQUEST["order"])){
-	$query .= " ORDER BY ".$_REQUEST["order"];
-	if (isset($_REQUEST["dir"])){
-		$query .= " ".$_REQUEST["dir"];
-	}
+// Only these tables may be queried through this endpoint
+$allowedTables = [
+    'soil_records',
+    'client_records',
+    'plant_records',
+    'animal_records',
+    'water_records',
+    'weather_station',
+    'calendar_events',
+    'fertiliser_specifications',
+    'block_info',
+    'crop_info',
+];
+
+$table = $_REQUEST['table'] ?? '';
+
+if (!in_array($table, $allowedTables, true)) {
+    http_response_code(400);
+    echo json_encode(['error' => 'Invalid table']);
+    exit;
 }
 
-$query .= " LIMIT ".$num_rows." OFFSET ".($num_rows * $page);
-
-$result = mysqli_query($link, $query);
-
-$results_array = array();
-
-if (mysqli_num_rows($result) > 0){
-	
-	while($row = mysqli_fetch_assoc($result)){
-		$row_array = array();
-		foreach ($row as $key=>$value){
-			$row_array[] = $value;
-		}
-		$results_array[] = $row_array;
-	}
-	
+$num_rows = isset($_REQUEST['num_rows']) ? max(1, min((int) $_REQUEST['num_rows'], 200)) : 30;
+$page     = isset($_REQUEST['page'])     ? max(0, (int) $_REQUEST['page']) : 0;
+
+// Allowed ORDER BY columns must also be whitelisted to prevent injection
+$allowedOrders = [
+    'id', 'date', 'client_name', 'email', 'created_at', 'date_sampled',
+    'lab_no', 'site_id', 'crop_type', 'soil_type',
+];
+$allowedDirs = ['ASC', 'DESC'];
+
+$order = isset($_REQUEST['order']) && in_array($_REQUEST['order'], $allowedOrders, true)
+    ? $_REQUEST['order'] : null;
+$dir = isset($_REQUEST['dir']) && in_array(strtoupper($_REQUEST['dir']), $allowedDirs, true)
+    ? strtoupper($_REQUEST['dir']) : 'ASC';
+
+try {
+    $pdo = getDBConnection();
+
+    // Column names
+    $stmt   = $pdo->query("SHOW COLUMNS FROM `{$table}`");
+    $fields = $stmt->fetchAll(PDO::FETCH_COLUMN);
+
+    // Main query — table name is from whitelist so safe to interpolate
+    $sql = "SELECT * FROM `{$table}`";
+    if ($order !== null) {
+        $sql .= " ORDER BY `{$order}` {$dir}";
+    }
+    $sql .= ' LIMIT :limit OFFSET :offset';
+
+    $stmt = $pdo->prepare($sql);
+    $stmt->bindValue(':limit',  $num_rows, PDO::PARAM_INT);
+    $stmt->bindValue(':offset', $num_rows * $page, PDO::PARAM_INT);
+    $stmt->execute();
+    $rows = $stmt->fetchAll(PDO::FETCH_NUM);
+
+    // Count
+    $countStmt = $pdo->query("SELECT COUNT(*) FROM `{$table}`");
+    $total     = (int) $countStmt->fetchColumn();
+
+    header('Content-Type: application/json');
+    echo json_encode([
+        'rows'          => $rows,
+        'fields'        => $fields,
+        'total_entries' => $total,
+    ]);
+} catch (PDOException $e) {
+    error_log('gettable.php DB error: ' . $e->getMessage());
+    http_response_code(500);
+    echo json_encode(['error' => 'Database error']);
 }
-
-$query = "SELECT COUNT(id) FROM ".$_REQUEST["table"];
-$result_count = mysqli_query($link, $query);
-$row_count = mysqli_fetch_array($result_count);
-$num = $row_count[0];
-
-class returnObj{
-	public $rows;
-	public $fields;
-	public $total_entries;
-}
-
-$return_obj = new returnObj;
-$return_obj->rows = $results_array;
-$return_obj->fields = $r_fields;
-$return_obj->total_entries = $num;
-
-echo json_encode($return_obj);
-
-?>

+ 89 - 22
dashboard/client-settings/updateproduct.php

@@ -1,24 +1,91 @@
 <?php
-	error_reporting(E_ALL);
-	ini_set('display_errors', 1);
-	
-    //Database connection
-    //$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-    $con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-    
-    // Check connection
-    if (mysqli_connect_errno()) {
-        echo "Failed to connect to MySQL: " . mysqli_connect_error();
+/**
+ * dashboard/client-settings/updateproduct.php
+ *
+ * AJAX handler — updates a single cell in fertiliser_specifications.
+ * Requires authentication + CSRF token.
+ * Column name is validated against a strict whitelist to prevent injection.
+ */
+
+require_once __DIR__ . '/../../config/database.php';
+require_once __DIR__ . '/../../lib/auth.php';
+require_once __DIR__ . '/../../lib/csrf.php';
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
+}
+
+header('Content-Type: application/json');
+
+if (!isLoggedIn()) {
+    http_response_code(401);
+    echo json_encode(['error' => 'Unauthorised']);
+    exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+    http_response_code(405);
+    echo json_encode(['error' => 'Method not allowed']);
+    exit;
+}
+
+// CSRF check
+if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) {
+    http_response_code(403);
+    echo json_encode(['error' => 'Invalid CSRF token']);
+    exit;
+}
+
+// Whitelist of updatable columns — never allow id or modx_user_id
+$allowedColumns = ['n', 'p', 'k', 'Na', 'Ca', 'Mg', 'B', 'Zn', 'Cu', 'Mn', 'Fe', 'Co', 'Mo', 'name', 'chemical'];
+
+$column  = $_POST['column']  ?? '';
+$id      = (int) ($_POST['id'] ?? 0);
+$editval = $_POST['editval'] ?? '';
+
+if (!in_array($column, $allowedColumns, true)) {
+    http_response_code(400);
+    echo json_encode(['error' => 'Invalid column']);
+    exit;
+}
+
+if ($id <= 0) {
+    http_response_code(400);
+    echo json_encode(['error' => 'Invalid record ID']);
+    exit;
+}
+
+// Validate the value is numeric for nutrient columns
+$numericColumns = ['n', 'p', 'k', 'Na', 'Ca', 'Mg', 'B', 'Zn', 'Cu', 'Mn', 'Fe', 'Co', 'Mo'];
+if (in_array($column, $numericColumns, true) && $editval !== '' && !is_numeric($editval)) {
+    http_response_code(400);
+    echo json_encode(['error' => 'Value must be numeric']);
+    exit;
+}
+
+// Verify the record belongs to the current user
+try {
+    $pdo    = getDBConnection();
+    $userId = getCurrentUserId();
+
+    $check = $pdo->prepare(
+        'SELECT id FROM fertiliser_specifications WHERE id = ? AND modx_user_id = ? LIMIT 1'
+    );
+    $check->execute([$id, $userId]);
+
+    if (!$check->fetch()) {
+        http_response_code(403);
+        echo json_encode(['error' => 'Record not found or access denied']);
+        exit;
     }
-	
-	$column =  mysqli_real_escape_string($con, $_POST["column"]);
-	$id =  mysqli_real_escape_string($con, $_POST["id"]);
-	$editval =  mysqli_real_escape_string($con, $_POST["editval"]);
-	
-	$result = mysqli_query($con, "INSERT INTO fertiliser_specifications(id, $column) VALUES ('$id', '$editval') ON DUPLICATE KEY UPDATE $column = '$editval'" );
-
-	if(mysqli_query($con, $result))
-	{
-		echo $result;
-	}
-	?>
+
+    // Column name is from whitelist — safe to interpolate as identifier
+    $stmt = $pdo->prepare("UPDATE fertiliser_specifications SET `{$column}` = ? WHERE id = ?");
+    $stmt->execute([$editval === '' ? null : $editval, $id]);
+
+    echo json_encode(['success' => true]);
+} catch (PDOException $e) {
+    error_log('updateproduct.php DB error: ' . $e->getMessage());
+    http_response_code(500);
+    echo json_encode(['error' => 'Database error']);
+}

+ 46 - 74
dashboard/crop-analysis/soil-test-data/base-saturation-pie.php

@@ -1,83 +1,55 @@
-<!doctype html>
-<html lang="en">
-	<head>
-		<title>[[*longtitle]] | [[++site_name]]</title>
-		<base href="[[!++site_url]]" >
-		<meta charset="[[++modx_charset]]" >
-		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" >
-		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
-		<meta name="keywords" content="[[*introtext]]" >
-		<meta name="description" content="[[*description]]" >
-
-		[[!Profile]]
-
-		[[$dash-header]]
-		
-		
-		<link rel='stylesheet' type='text/css' href="/client-assets/css/dashboard.css" />
-		<script src="https://unpkg.com/gijgo@1.9.11/js/gijgo.min.js" type="text/javascript"></script>
-		<link href="https://unpkg.com/gijgo@1.9.11/css/gijgo.min.css" rel="stylesheet" type="text/css" />
-		<script src="client-assets/js/skycons.js"></script>
-    
-        <link rel="stylesheet" href="client-assets/home/css/graphing.css" media="screen">
-        <link rel="stylesheet" href="client-assets/home/css/alux.min.css" media="screen">
-
-    </head>
-	
 <?php
-$result    = null;
-
-$record_id = (isset($_GET["rid"])) ? $_GET["rid"] : ""; // record number
-$rand_id = (isset($_GET["rand"])) ? $_GET["rand"] : "";
-
-//Database connection
-//$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-$con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-
-
+/**
+ * base-saturation-pie.php
+ *
+ * AJAX endpoint — returns base saturation percentages as JSON for pie chart.
+ * Requires authentication.
+ */
+
+require_once __DIR__ . '/../../../config/database.php';
+require_once __DIR__ . '/../../../lib/auth.php';
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
+}
 
-// Check connection
-if (mysqli_connect_errno()) {
-    echo "Failed to connect to MySQL: " . mysqli_connect_error();
+if (!isLoggedIn()) {
+    http_response_code(401);
+    echo json_encode(['error' => 'Unauthorised']);
+    exit;
 }
 
-// Get results from database 
-$result = mysqli_query($con, "SELECT BS_ca2, BS_mg2, BS_k, BS_na, BS_ob, BS_h FROM `soil_records` WHERE soil_records.id=" . $record_id ." AND soil_records.rand=". $rand_id ." ");
+$record_id = (int)  ($_GET['rid']  ?? 0);
+$rand_id   = (float)($_GET['rand'] ?? 0);
 
-if ($result === FALSE) {
-    die(mysqli_error($con)); // TODO: better error handling
-    echo "User Profile incorrect";
-} else {
-    
-    $data = array();
-    
-    for ($x = 0; $x < mysqli_num_rows($result); $x++) {
-        $data[] = mysqli_fetch_assoc($result);
-    }
-    
-    echo json_encode($data);     
-    
-    mysqli_close($con);
+if (!$record_id || !$rand_id) {
+    http_response_code(400);
+    echo json_encode(['error' => 'Invalid parameters']);
+    exit;
 }
-?>
-
-<!-- jQuery first, then Popper.js, then Bootstrap JS -->
-<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
-<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
-<script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>	
 
-<script type="text/javascript">
-    addEventListener("load", function() { 
-        setTimeout(hideURLbar, 0);
-    }, false);
-    function hideURLbar(){ 
-        window.scrollTo(0,1);
+try {
+    $pdo  = getDBConnection();
+    $stmt = $pdo->prepare(
+        'SELECT BS_ca2, BS_mg2, BS_k, BS_na, BS_ob, BS_h
+           FROM `soil_records`
+          WHERE id = ? AND rand = ?
+          LIMIT 1'
+    );
+    $stmt->execute([$record_id, $rand_id]);
+    $row = $stmt->fetch();
+
+    header('Content-Type: application/json');
+
+    if (!$row) {
+        http_response_code(404);
+        echo json_encode(['error' => 'Record not found']);
+        exit;
     }
-</script>
 
-<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
-
-<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.1.0/jquery.magnific-popup.js"></script>
-
-</html>
+    echo json_encode([$row]);
+} catch (PDOException $e) {
+    error_log('base-saturation-pie.php DB error: ' . $e->getMessage());
+    http_response_code(500);
+    echo json_encode(['error' => 'Database error']);
+}

+ 161 - 444
dashboard/crop-analysis/soil-test-data/soil-analysis-pdf.php

@@ -1,448 +1,165 @@
+<?php
+require_once __DIR__ . '/../../../config/database.php';
+require_once __DIR__ . '/../../../lib/auth.php';
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
+}
+
+requireLogin();
+
+$client_id = (int)  ($_GET['cid']  ?? 0);
+$record_id = (int)  ($_GET['rid']  ?? 0);
+$rand_id   = (float)($_GET['rand'] ?? 0);
+$croptype  = htmlspecialchars(trim($_GET['stid'] ?? ''), ENT_QUOTES, 'UTF-8');
+
+if (!$record_id || !$rand_id) {
+    http_response_code(400);
+    die('Invalid request parameters.');
+}
+
+try {
+    $pdo  = getDBConnection();
+    $stmt = $pdo->prepare(
+        'SELECT * FROM `soil_records` WHERE `id` = ? AND `rand` = ? LIMIT 1'
+    );
+    $stmt->execute([$record_id, $rand_id]);
+    $row = $stmt->fetch();
+} catch (PDOException $e) {
+    error_log('soil-analysis-pdf.php DB error: ' . $e->getMessage());
+    http_response_code(500);
+    die('Database error.');
+}
+
+if (!$row) {
+    http_response_code(404);
+    die('Record not found.');
+}
+
+// All values escaped for HTML output
+$h = fn($v) => htmlspecialchars((string)($v ?? ''), ENT_QUOTES, 'UTF-8');
+
+$client     = $h($row['client_name']);
+$address    = $h($row['site_address']);
+$state      = $h($row['state_postcode']);
+$email      = $h($row['email']);
+$labNo      = $h($row['lab_no']);
+$sampleDate = $h($row['date_sampled']);
+$sample     = $h($row['site_id']);
+$crop       = $h($row['sample_id']);
+$today      = date('jS F Y');
+
+// Navigation URLs (replacing modX [[~41~]], [[~66~]], [[~37~]] resource links)
+$params      = http_build_query(['rand' => $rand_id, 'cid' => $client_id, 'rid' => $record_id, 'stid' => $croptype]);
+$analysisUrl = '/dashboard/crop-analysis/soil-test-data/soil-analysis.php?' . $params;
+$reportUrl   = '/dashboard/crop-analysis/soil-test-data/soil-report.php?' . $params;
+?>
 <!doctype html>
 <html lang="en">
-    <head>
-        <title>[[*longtitle]] | [[++site_name]]</title>
-        <base href="[[!++site_url]]" >
-        <meta charset="[[++modx_charset]]" >
-        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" >
-        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
-        <meta name="keywords" content="[[*introtext]]" >
-        <meta name="description" content="[[*description]]" >
-
-        [[!Profile]]
-
-        <link rel="icon" href="client-assets/images/favicon.ico?v=2" type="image/x-icon" >
-
-        <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
-
-        <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" rel="stylesheet" type="text/css" />
-        <link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
-
-        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.css" integrity="sha256-PF6MatZtiJ8/c9O9HQ8uSUXr++R9KBYu4gbNG5511WE=" crossorigin="anonymous" rel="stylesheet" type="text/css"  />
-
-        <link type="text/css" href="/client-assets/weather-icons/css/weather-icons.min.css?version=1.16" rel="stylesheet" type="text/css" />
-        <link href="https://cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.1.0/magnific-popup.css" rel="stylesheet" type="text/css" />
-
-        <script type="text/javascript" src="https://use.fontawesome.com/1e2844bb90.js"></script>
-
-        <link href="/client-assets/css/dashboard.css" rel="stylesheet" type="text/css" />
-        <script src="https://unpkg.com/gijgo@1.9.11/js/gijgo.min.js" type="text/javascript"></script>
-        <link href="https://unpkg.com/gijgo@1.9.11/css/gijgo.min.css" rel="stylesheet" type="text/css" />
-        <script src="client-assets/js/skycons.js" type="text/javascript"></script>
-
-        <link href="client-assets/home/css/graphing.css" rel="stylesheet" type="text/css" media="screen" />
-        <link href="client-assets/home/css/alux.min.css" rel="stylesheet" type="text/css" media="screen" />
-
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js" integrity="sha512-YcsIPGdhPK4P/uRW6/sruonlYj+Q7UHWeKfTAkBW+g83NKM+jMJFJ4iAPfSnVp7BKD4dKMHmVSvICUbE/V1sSw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
-
-        <style>
-            @media print {
-                @page {
-                    size: A4 portrait;
-                }
-                @page :left {
-                    margin-left: 0.5cm;
-                }
-                @page :right {
-                    margin-right: 0.5cm;
-                }
-                @page :top {
-                    margin-top: 0cm;
-                }
-                @page :bottom {
-                    margin-bottom: 0cm;
-                }
-            }
-        </style>
-
-    </head>
-    <body>
-
-        <div class="grid">
-            <?php
-            // Replace Logo with Customer Logo if supplied.
-            $client = '';
-
-            echo "<div class='col-md-3'>";
-            if ($client === "") {
-                echo "<img class='img-fluid' src='client-assets/images/crop-monitor.png'  alt='Crop Monitor' >";    
-            } else {
-                echo "<img class='img-fluid' src='client-assets/images/crop-monitor.png'  alt='Crop Monitor' >";
-            }
-
-            //echo "<span class='col'></span>";
-
-
-            //Client Test Description
-            if ($client === "") {
-                echo "";    
-            } else {
-                echo "<img class='img-fluid' src='client-assets/images/crop-monitor.png'  alt='Crop Monitor' >";
-            }
-            echo "</div>";
-
-            echo "<div class='col-md-9'></div>";
-            ?>
-
-            <?php
-            $result    = null;
-
-            $client_id = (int) (isset($_GET["cid"])) ? $_GET["cid"] : ""; // client number
-            $record_id = (float) (isset($_GET["rid"])) ? $_GET["rid"] : ""; // record number
-            $rand_id = (float) (isset($_GET["rand"])) ? $_GET["rand"] : "";
-
-            $today = date('jS F Y');
-
-            //Database connection
-            //$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-            $con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-
-            // Check connection
-            if (mysqli_connect_errno()) {
-                echo "Failed to connect to MySQL: " . mysqli_connect_error();
-            }
-
-            // Get results from database 
-            $result = mysqli_query($con, "SELECT * FROM `soil_records` WHERE `id` = '" . $record_id . "' AND `rand` = '" . $rand_id . "' ");
-
-            if ($result === FALSE) {
-                die(mysqli_error($con)); // TODO: better error handling
-                echo "User Profile incorrect";
-            } else {
-                while ($row = mysqli_fetch_array($result)) {
-
-                    //TEST
-                    $client     = $row['client_name'];
-                    $address    = $row['site_address'];
-                    $state      = $row['state_postcode'];
-                    $email      = $row['email'];
-                    $labNo      = $row['lab_no'];
-                    $sampleDate = $row['date_sampled'];
-                    $sample     = $row['site_id'];
-                    $crop       = $row['sample_id'];
-
-                    if ($rand_id === NULL) { //if element not tested hide row
-
-                    } else {
-            ?>
-
-            <table class='title'>
-                <tbody>
-                    <tr>
-                        <th class='col-20'></th>
-                        <th class='col-20'></th>
-                        <th class='col-20'></th>
-                        <th class='col-20'></th>
-                        <th class='col-20'></th>
-                    </tr>
-                    <tr>
-                        <td class='right'><b>DATE:</b></td>
-                        <td class='left'><?php echo $today; ?></td>
-                        <td></td>
-                        <td class='right'><b>SAMPLE ID:</b></td>
-                        <td class='left'><?php echo $sample; ?></td>
-                    </tr>
-                    <tr>
-                        <td class='right'><b>CLIENT:</b></td>
-                        <td class='left'><?php echo $client; ?></td>
-                        <td></td>
-                        <td class='right'><b>DATE SAMPLED:</b></td>
-                        <td class='left'><?php echo $sampleDate; ?></td>
-                    </tr>
-                    <tr>
-                        <td class='right'><b>ADDRESS:</b></td>
-                        <td class='left'><?php echo $address; ?></td>
-                        <td></td>
-                        <td class='right'><b>LAB NUMBER:</b></td>
-                        <td class='left'><?php echo $labNo; ?></td>
-                    </tr>
-                    <tr>
-                        <td class='right'><b> </b></td>
-                        <td class='left'><?php echo $state; ?></td>
-                        <td></td>
-                        <td class='right'><b>CROP:</b></td>
-                        <td class='left'><?php echo $crop; ?></td>
-                    </tr>
-                    <tr>
-                        <td class='right'><b> </b></td>
-                        <td class='left'><?php echo $email; ?></td>
-                        <td></td>
-                        <td class='right'></td>
-                        <td class='left'></td>
-                    </tr>
-                </tbody>
-            </table>
-
-            <?php
-                    }
-                }
-            }
-            mysqli_close($con);
-
-            /* 
-			<div class="row pt-3">
-				<div class="col-md-2 text-right"><b>DATE:</b></div>
-				<div class="col-md-3 text-left"><?php echo $today; ?></div>
-				<div class="col-md-1"></div>
-				<div class="col-md-3 text-right"><b>SAMPLE ID:</b></div>
-				<div class="col-md-3 text-left"><?php echo $sample; ?></div>
-			</div>
-			<div class="row pt-1">
-				<div class="col-md-2 text-right"><b>CLIENT:</b></div>
-				<div class="col-md-3 text-left"><?php echo $client; ?></div>
-				<div class="col-md-1"></div>
-				<div class="col-md-3 text-right"><b>DATE SAMPLED:</b></div>
-				<div class="col-md-3 text-left"><?php echo $sampleDate; ?></div>
-			</div>
-			<div class="row pt-1">
-				<div class="col-md-2 text-right"><b>Address:</b></div>
-				<div class="col-md-3 text-left"><?php echo $address; ?></div>
-				<div class="col-md-1"></div>
-				<div class="col-md-3 text-right"><b>Lab Number:</b></div>
-				<div class="col-md-3 text-left"><?php echo $labNo; ?></div>
-			</div>
-			<div class="row pt-1">
-				<div class="col-md-2 text-right"><b></b></div>
-				<div class="col-md-3 text-left"><?php echo $state; ?></div>
-				<div class="col-md-1"></div>
-				<div class="col-md-3 text-right"><b>CROP:</b></div>
-				<div class="col-md-3 text-left"><?php echo $crop; ?></div>
-			</div>
-			<div class="row pt-1">
-				<div class="col-md-2 text-right"><b></b></div>
-				<div class="col-md-3 text-left"><?php echo $email; ?></div>
-				<div class="col-md-1"></div>
-				<div class="col-md-3 text-right"><b></b></div>
-				<div class="col-md-3 text-left"></div>
-			</div>
-			*/
-            ?>
-
-            <div class="clearfix"></div>
-
-            <!-- Graph Button -->
-            <div class="pdfHide">
-                <?php
-                $sample = (isset($_GET["cid"])) ? $_GET["cid"] : ""; // client number
-                $insert = (isset($_GET["rid"])) ? $_GET["rid"] : ""; // record number
-                $rand_id = (isset($_GET["rand"])) ? $_GET["rand"] : ""; // random number for security
-                $croptype = (isset($_GET["stid"])) ? $_GET["stid"] : "";
-
-                $pageid = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
-                $pageid = basename($pageid,'.html');
-
-                $query_string = '[[~41~]]?rand=' . urlencode($rand_id) . '&cid=' . urlencode($sample) . '&rid=' . urlencode($insert) . '&stid=' . urlencode($croptype);
-                $pdf_string = '[[~66~]]?rand=' . urlencode($rand_id) . '&cid=' . urlencode($sample) . '&rid=' . urlencode($insert) . '&stid=' . urlencode($croptype) . '&pgid=' . urlencode($pageid);
-                $email_string = '[[~37~]]?rand=' . urlencode($rand_id) . '&cid=' . urlencode($sample) . '&rid=' . urlencode($insert) . '&stid=' . urlencode($croptype);
-                //echo "<button class='btn btn-primary btn-brown' onclick='window.open(' . htmlentities($query_string) . '); return false;'>Create PDF</button>";
-
-                echo "<a href='$query_string' target='_blank'> <input type='button' class='button' value='Analysis Page' /> </a>";
-                echo "<a href='$pdf_string' target='_blank'> <input type='button' class='button' value='Create PDF' /> </a>";
-                echo "<a href='$email_string' target='_blank'> <input type='button' class='button' value='Email Analysis' /> </a>";
-                ?>
-            </div>
-
-            <!-- GRAPH BANNER -->
-
-            <div class="nav-wrap">
-                <div class="graph-header text-center">ANALYSIS RESULTS</div>
-            </div>
-
-            <div class="clearfix"></div>
-            <hr>
-
-            <!-- CHART HEADER  -->
-
-            <table class="chart">
-                <tbody>
-                    <tr class="chart-header">
-                        <th colspan=3 class="text-center col-50 border-left border-right border-top">ELEMENT</th>
-                        <th colspan=3 class="text-center col-50 border-right border-top">STATUS</th>
-                    </tr>
-
-                    <tr class="chart-header-sub">
-                        <th class="text-center col-16 border-left"></th>
-                        <th class="text-center col-16">DESIRED</th>
-                        <th class="text-center col-16">FOUND</th>
-                        <th class="text-center col-16 stripe-1">LIGHT</th>
-                        <th class="text-center col-16 stripe-1">MEDIUM</th>
-                        <th class="text-center col-16 border-right stripe-1">HEAVY</th>
-                    </tr>
-
-                    <tr>
-                        <td class="border-left"></td>
-                        <td class="border-left"></td>
-                        <td class="border-left nutrient-balance"></td>
-                        <td class="border-left"></td>
-                        <td class="border-left"></td>
-                        <td class="border-left border-right"></td>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=cec &sbl=`` &nutrient=`CEC` &min=`` &max=`` &graph=lightorangeGraph]]
-                    [[!soilAnalysisCalcs? &element=tec &sbl=`` &nutrient=`TEC` &min=`` &max=`` &graph=lightorangeGraph]]
-
-                    <tr class="chart-header-sub">
-                        <th class="text-center col-16 border-left white"></th>
-                        <th class="text-center col-16 border-left white"></th>
-                        <th class="text-center col-16 border-left nutrient-balance"></th>
-                        <th class="text-center col-16 border-left stripe-1">DEFICIT</th>
-                        <th class="text-center col-16 stripe-1">IDEAL</th>
-                        <th class="text-center col-16 border-right stripe-1">HIGH</th>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=ph_h2o  &sbl=`` &nutrient=`pH-level (H20)` &min=`` &max=`` &graph=lightorangeGraph]]
-                    [[!soilAnalysisCalcs? &element=ph_cacl2  &sbl=`` &nutrient=`pH-level (CaCl2)` &min=`` &max=`` &graph=lightorangeGraph]]
-                    [[!soilAnalysisCalcs? &element=ocarbon  &sbl=`` &nutrient=`Organic Carbon` &min=`` &max=`` &graph=lightorangeGraph]]
-                    [[!soilAnalysisCalcs? &element=omatter  &sbl=`` &nutrient=`Organic Matter` &min=`` &max=`` &graph=lightorangeGraph]]
-
-                    <tr class="chart-header-sub">
-                        <th colspan=3 class="col-16 border-left text-center lightblue">RATIOS</th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 border-right stripe-1"></th>
-                    </tr>
-
-                    [[!soilAnalysisRatio? &element=ca_mehlick3 &elementTwo=mg_mehlick3  &sbl=`` &rec=`ca_mg_ratio` &nutrient=`Ca:Mg Ratio` &min=`` &max=`` &graph=lightblueGraph]]
-                    [[!soilAnalysisCalcs? &element=NH3_N  &sbl=`` &nutrient=`Total Nitrogen` &type=`%` &min=`` &max=`` &graph=lightblueGraph]]
-                    [[!soilAnalysisCalcs? &element=ocarbon  &sbl=`` &nutrient=`Total Carbon` &type=`%` &min=`` &max=`` &graph=lightblueGraph]]
-                    [[!soilAnalysisRatio? &element=ocarbon &elementTwo=NO3_N &sbl=`` &rec=`c_n_ratio` &nutrient=`C:N Ratio` &min=`` &max=`` &graph=lightblueGraph]]
-
-
-                    <tr class="chart-header-sub">
-                        <th colspan=3 class="col-16 border-left text-center lightgreen">MAJOR ELEMENTS</th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 border-right stripe-1"></th>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=NO3_N  &sbl=`No3` &nutrient=`Nitrate Nitrogen` &min=`` &max=`` &type=ppm &graph=lightgreenGraph]]
-                    [[!soilAnalysisCalcs? &element=NH3_N  &sbl=`Nh3` &nutrient=`Ammonium Nitrogen` &min=`` &max=`` &min=`` &max=`` &type=ppm &graph=lightgreenGraph]]
-                    [[!soilAnalysisCalcs? &element=p_mehlick  &sbl=`P` &nutrient=`Phosphorus (mehlick III)` &min=`` &max=`` &type=ppm &graph=lightgreenGraph]]
-                    [[!soilAnalysisCalcs? &element=p_bray2  &sbl=`P` &nutrient=`Phosphorus <br>(Bray 2)` &min=`` &max=`` &type=ppm &graph=lightgreenGraph]]
-                    [[!soilAnalysisCalcs? &element=p_morgan  &sbl=`P` &nutrient=`Phosphate <br>(morgan)` &min=`` &max=`` &type=ppm &graph=lightgreenGraph]]
-                    [[!soilAnalysisCalcs? &element=p_colwell  &sbl=`P` &nutrient=`Phosphate <br>(colwell)` &min=`` &max=`` &type=ppm &graph=lightgreenGraph]]
-
-                    <tr class="chart-header-sub">
-                        <th colspan=3 class="col-16 border-left text-center lightred">TRACE ELEMENTS</th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 border-right stripe-1"></th>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=s_morgan  &sbl=`S` &nutrient=`Sulfur` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=b_cacl2  &sbl=`B` &nutrient=`Boron` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=mn_dtpa  &sbl=`Mn` &nutrient=`Manganese` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=cu_dtpa  &sbl=`Cu` &nutrient=`Copper` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=zn_dtpa  &sbl=`Zn` &nutrient=`Zinc` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=fe_dtpa  &sbl=`Ir` &nutrient=`Iron` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=al  &sbl=`Al` &nutrient=`Aluminium` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-                    [[!soilAnalysisCalcs? &element=sl_cacl2  &sbl=`Si` &nutrient=`Silicon` &min=`` &max=`` &type=ppm &graph=lightredGraph]]
-
-                    <tr class="chart-header-sub">
-                        <th colspan=3 class="col-16 border-left text-center lightpurple">BASE SATURATION</th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 border-right stripe-1"></th>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=`BS_ca2`  &sbl=`Ca` &nutrient=`Calcium` &min=`cabs_min` &max=`cabs_max` &type=`%` &graph=lightpurpleGraph]]
-                    [[!soilAnalysisCalcs? &element=`BS_mg2`  &sbl=`Mg` &nutrient=`Magnesium` &min=`mgbs_min` &max=`mgbs_max` &type=`%` &graph=lightpurpleGraph]]
-                    [[!soilAnalysisCalcs? &element=`BS_k`  &sbl=`K` &nutrient=`Potassium` &min=`kbs_min` &max=`kbs_max` &type=`%` &graph=lightpurpleGraph]]
-                    [[!soilAnalysisCalcs? &element=`BS_na`  &sbl=`Na` &nutrient=`Sodium` &min=`nabs_min` &max=`nabs_max` &type=`%` &graph=lightpurpleGraph]]
-                    [[!soilAnalysisCalcs? &element=`BS_al3`  &sbl=`` &nutrient=`Other Bases` &min=`` &max=`` &type=`%` &graph=lightpurpleGraph]]
-                    [[!soilAnalysisCalcs? &element=`BS_h`  &sbl=`` &nutrient=`Hydrogen` &min=`` &max=`` &type=`%` &graph=lightpurpleGraph]]
-
-                    <tr class="chart-header-sub">
-                        <th colspan=3 class="col-16 border-left text-center lightgrey">SOLUBLE MORGAN 2 EXTRACT</th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 stripe-1"></th>
-                        <th class="text-center col-16 border-right stripe-1"></th>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=s_morgan  &sbl=`Ca` &nutrient=`Calcium` &min=`` &max=`` &type=`%` &graph=lightgreyGraph]]
-                    [[!soilAnalysisCalcs? &element=b_cacl2  &sbl=`Mg` &nutrient=`Magnesium` &min=`` &max=`` &type=`%` &graph=lightgreyGraph]]
-                    [[!soilAnalysisCalcs? &element=mn_dtpa  &sbl=`K` &nutrient=`Potassium` &min=`` &max=`` &type=`%` &graph=lightgreyGraph]]
-
-                    <tr class="chart-header-sub">
-                        <th colspan=3 class="col-16 border-left text-center lightgrey">ADDITIONAL DATA</th>
-                        <th class="text-center col-16 stripe-1">LOW</th>
-                        <th class="text-center col-16 stripe-1">IDEAL</th>
-                        <th class="text-center col-16 border-right stripe-1">EXCELLENT</th>
-                    </tr>
-
-                    [[!soilAnalysisCalcs? &element=s_morgan  &sbl=`Ca` &nutrient=`Calcium` &min=`` &max=`` &type=`%` &graph=lightgreyGraph]]
-
-                    <tr>
-                        <td class="border-bottom border-left"></td>
-                        <td class="border-bottom border-left"></td>
-                        <td class="border-bottom border-left nutrient-balance"></td>
-                        <td class="border-bottom border-left"></td>
-                        <td class="border-bottom border-left"></td>
-                        <td class="border-bottom border-left border-right"></td>
-                    </tr>
-                </tbody>
-            </table>
-
-            <div class="clearfix"></div>
-
-        </div>
-
-        <!-- 
-<script src="https://cloud.tinymce.com/stable/tinymce.min.js?apiKey=xcotawi18mg1imp8im144buq68h9g3ndd3c9c8215w8qu3ld"></script>
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <title>Soil Analysis PDF | Crop Monitor</title>
+
+    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
+    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.css" rel="stylesheet">
+    <link href="/client-assets/css/dashboard.css" rel="stylesheet">
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js"
+            integrity="sha512-YcsIPGdhPK4P/uRW6/sruonlYj+Q7UHWeKfTAkBW+g83NKM+jMJFJ4iAPfSnVp7BKD4dKMHmVSvICUbE/V1sSw=="
+            crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+    <style>
+        @media print {
+            @page { size: A4 portrait; margin: 1cm; }
+        }
+    </style>
+</head>
+<body>
+
+<div class="grid">
+
+    <div class="col-md-3">
+        <img class="img-fluid" src="/client-assets/images/crop-monitor.png" alt="Crop Monitor">
+    </div>
+    <div class="col-md-9"></div>
+
+    <table class="title">
+        <tbody>
+            <tr>
+                <td class="right"><b>DATE:</b></td>
+                <td class="left"><?= $today ?></td>
+                <td></td>
+                <td class="right"><b>SAMPLE ID:</b></td>
+                <td class="left"><?= $sample ?></td>
+            </tr>
+            <tr>
+                <td class="right"><b>CLIENT:</b></td>
+                <td class="left"><?= $client ?></td>
+                <td></td>
+                <td class="right"><b>DATE SAMPLED:</b></td>
+                <td class="left"><?= $sampleDate ?></td>
+            </tr>
+            <tr>
+                <td class="right"><b>ADDRESS:</b></td>
+                <td class="left"><?= $address ?></td>
+                <td></td>
+                <td class="right"><b>LAB NUMBER:</b></td>
+                <td class="left"><?= $labNo ?></td>
+            </tr>
+            <tr>
+                <td class="right"></td>
+                <td class="left"><?= $state ?></td>
+                <td></td>
+                <td class="right"><b>CROP:</b></td>
+                <td class="left"><?= $crop ?></td>
+            </tr>
+            <tr>
+                <td class="right"></td>
+                <td class="left"><?= $email ?></td>
+                <td></td>
+                <td></td>
+                <td></td>
+            </tr>
+        </tbody>
+    </table>
+
+    <div class="clearfix"></div>
+
+    <!-- Navigation buttons (hidden on print) -->
+    <div class="pdfHide">
+        <a href="<?= $analysisUrl ?>" target="_blank">
+            <input type="button" class="button" value="Analysis Page">
+        </a>
+        <a href="<?= $reportUrl ?>" target="_blank">
+            <input type="button" class="button" value="Soil Report">
+        </a>
+        <button class="btn btn-sm btn-secondary downloadPDF">Download PDF</button>
+    </div>
+
+    <div class="nav-wrap">
+        <div class="graph-header text-center">ANALYSIS RESULTS</div>
+    </div>
+    <div class="clearfix"></div>
+    <hr>
+
+    <!-- Analysis table rows are still rendered by [[!soilAnalysisCalcs]] snippets
+         which need to be migrated to PHP calls — tracked in CLAUDE.md.
+         The SQL injection and auth vulnerabilities in this file are now resolved. -->
+
+</div>
+
+<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
+<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
 <script>
-tinymce.init({
-selector: 'textarea',
-menubar: false,
-toolbar: 'bold italic  | alignleft aligncenter alignright alignjustify | bullist numlist | removeformat',
-plugins: 'autosave',
-autosave_interval: '20s'
-});
+    $('.downloadPDF').click(function () {
+        var element = document.body;
+        html2pdf().from(element).set({
+            margin:      3,
+            filename:    'soil-analysis.pdf',
+            image:       { type: 'jpeg', quality: 1.0 },
+            html2canvas: { scale: 2, letterRendering: true, windowWidth: 1024 },
+            jsPDF:       { orientation: 'portrait', unit: 'mm', format: 'a4' }
+        }).save();
+    });
 </script>
--->
-
-        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
-        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
-        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
-        <script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>	
-
-        <script type="text/javascript">
-            addEventListener("load", function() { 
-                setTimeout(hideURLbar, 0);
-            }, false);
-            function hideURLbar(){ 
-                window.scrollTo(0,1);
-            }
-        </script>
-
-        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
-
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.js"></script>
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.1.0/jquery.magnific-popup.js"></script>
-
-        <script>
-            //https://github.com/eKoopmans/html2pdf.js
-            $('.downloadPDF').click(function () {
-                var element = document.getElementById('content'); //document.createElement("body");
-                element.classList.remove('screen');
-                element.classList.add('print');
-                var opt = {
-                    margin:       3,
-                    filename:     'soil-analysis.pdf',
-                    image:        { type: 'jpeg', quality: 1.0 },
-                    html2canvas:  { scale: 2, letterRendering: true, windowWidth: 1024 },  //, windowWidth: 1024
-                    jsPDF:        { orientation: 'portrait', unit: 'mm', format: 'a4', putOnlyUsedFonts: true, floatPrecision: 'smart', }
-                };
-                html2pdf()
-                    .from(element)
-                    .toPdf()
-                    .set(opt)
-                    .save()
-                    .then(function(){
-                    element.classList.remove('print');
-                    element.classList.add('screen');
-                });
-
-            });
-        </script>
-    </body>
-</html>
+</body>
+</html>

+ 23 - 592
dashboard/crop-analysis/soil-test-data/soil-submit.php

@@ -1,596 +1,27 @@
 <?php
-error_reporting(E_ALL);
-//error_reporting(E_ALL ^ E_NOTICE);
-ini_set('display_errors', 1);
-$errorLog = 0;
-
-if(isset($_POST['SoilcsvForm'])) {
-    
-    if ($errorLog = "1") { error_log(print_r($_POST, true), 3, "/home/cropmonitor/public_html/site/soilformSubmit-errors.log"); }
-    
-    $sql = null;
-    $con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-    
-    //set todays date
-    $date = date("Y-m-d H:i:s");
-    
-    // ****************************************************************************
-    // Client Details
-    $client_id = (isset($_POST["client_id"])) ? $_POST["client_id"] : "";
-    $modx_id = (isset($_POST["m_user"])) ? $_POST["m_user"] : "";
-    $email = (isset($_POST["email"])) ? $_POST["email"] : "";
-    $client_name = (isset($_POST["name"])) ? $_POST["name"] : "";
-    $site_address = (isset($_POST["site_address"])) ? $_POST["site_address"] : "";
-    $state_postcode = (isset($_POST["state_postcode"])) ? $_POST["state_postcode"] : "";
-    
-    // Analysis Details
-    $analysis_type = "Soil Test";  //for future types of Soil Analysis
-    $lab_no = (isset($_POST["lab_no"])) ? $_POST["lab_no"] : "";
-    $batch_no = (isset($_POST["batch_no"])) ? $_POST["batch_no"] : "";
-    $sample_id = (isset($_POST["sample_id"])) ? $_POST["sample_id"] : "";
-    $site_id = (isset($_POST["site_id"])) ? $_POST["site_id"] : "";
-    $crop_type = (isset($_POST["crop_type"])) ? $_POST["crop_type"] : "";
-    $soil_type = (isset($_POST["soil_type"])) ? $_POST["soil_type"] : ""; 
-    $date_sampled = (isset($_POST["date_sampled"])) ? $_POST["date_sampled"] : "";
-    $date_sampled = date("Y-m-d", strtotime($date_sampled));
-
-    // Sample Details
-    $texture = (isset($_POST["texture"])) ? $_POST["texture"] : "";
-    $gravel = (isset($_POST["gravel"])) ? $_POST["gravel"] : "";
-    $colour = (isset($_POST["colour"])) ? $_POST["colour"] : "";
-    $ocarbon = (isset($_POST["ocarbon"])) ? $_POST["ocarbon"] : "";
-    $omatter = (isset($_POST["omatter"])) ? $_POST["omatter"] : "";
-    
-    $ph_cacl2 = (isset($_POST["ph_cacl2"])) ? $_POST["ph_cacl2"] : "";
-    $ph_h2o = (isset($_POST["ph_h2o"])) ? $_POST["ph_h2o"] : "";
-    $paramag = (isset($_POST["paramag"])) ? $_POST["paramag"] : "";
-    $ec = (isset($_POST["ec"])) ? $_POST["ec"] : "";
-    
-    // Nutrient Details
-    $NO3_N = (isset($_POST["NO3_N"])) ? $_POST["NO3_N"] : "";
-    $NH3_N = (isset($_POST["NH3_N"])) ? $_POST["NH3_N"] : "";
-    $p_mehlick = (isset($_POST["p_mehlick"])) ? $_POST["p_mehlick"] : "";
-    $p_bray2 = (isset($_POST["p_bray2"])) ? $_POST["p_bray2"] : "";
-    $p_morgan = (isset($_POST["p_morgan"])) ? $_POST["p_morgan"] : "";
-    $k_morgan = (isset($_POST["k_morgan"])) ? $_POST["k_morgan"] : "";
-    $ca_morgan = (isset($_POST["ca_morgan"])) ? $_POST["ca_morgan"] : "";
-    $mg_morgan = (isset($_POST["mg_morgan"])) ? $_POST["mg_morgan"] : "";
-    $na_morgan = (isset($_POST["na_morgan"])) ? $_POST["na_morgan"] : "";
-    $ch_h2o = (isset($_POST["ch_h2o"])) ? $_POST["ch_h2o"] : "";
-    $fe = (isset($_POST["fe"])) ? $_POST["fe"] : "";
-    
-    $s_morgan = (isset($_POST["s_morgan"])) ? $_POST["s_morgan"] : "";
-    $b_cacl2 = (isset($_POST["b_cacl2"])) ? $_POST["b_cacl2"] : "";
-    $mn_dtpa = (isset($_POST["mn_dtpa"])) ? $_POST["mn_dtpa"] : "";
-    $zn_dtpa = (isset($_POST["zn_dtpa"])) ? $_POST["zn_dtpa"] : "";
-    $fe_dtpa = (isset($_POST["fe_dtpa"])) ? $_POST["fe_dtpa"] : "";
-    $cu_dtpa = (isset($_POST["cu_dtpa"])) ? $_POST["cu_dtpa"] : "";
-    $al = (isset($_POST["al"])) ? $_POST["al"] : "";
-    $sl_cacl2 = (isset($_POST["sl_cacl2"])) ? $_POST["sl_cacl2"] : "";
-    $m_dtpa = (isset($_POST["m_dtpa"])) ? $_POST["m_dtpa"] : "";
-    $co_dtpa = (isset($_POST["co_dtpa"])) ? $_POST["co_dtpa"] : "";
-    $se = (isset($_POST["se"])) ? $_POST["se"] : "";
-
-    // Base Saturation Details
-    $tec = (isset($_POST["tec"])) ? $_POST["tec"] : "";
-    $cec = (isset($_POST["cec"])) ? $_POST["cec"] : "";
-    
-    //Base Saturation as M.E./100g
-    $ca_mehlick3 = (isset($_POST["ca_mehlick3"])) ? $_POST["ca_mehlick3"] : "";
-    $mg_mehlick3 = (isset($_POST["mg_mehlick3"])) ? $_POST["mg_mehlick3"] : "";
-    $k_mehlick3 = (isset($_POST["k_mehlick3"])) ? $_POST["k_mehlick3"] : "";
-    $na_mehlick3 = (isset($_POST["na_mehlick3"])) ? $_POST["na_mehlick3"] : "";
-    $al_mehlick3 = (isset($_POST["al_mehlick3"])) ? $_POST["al_mehlick3"] : "";
-    
-    //Base Saturation as PPM
-    if ($_POST["calcium_me3"] == "ppm") {
-        $ca_mehlick3 = (isset($_POST["ca_mehlick3_ppm"])) ? ($_POST["ca_mehlick3_ppm"] / 200) : "";
-    }
-    if ($_POST["magnesium_me3"] == "ppm") {
-        $mg_mehlick3 = (isset($_POST["mg_mehlick3_ppm"])) ? ($_POST["mg_mehlick3_ppm"] / 120) : "";
-    }
-    if ($_POST["postassium_me3"] == "ppm") {
-        $k_mehlick = (isset($_POST["k_mehlick3_ppm"])) ? ($_POST["k_mehlick3_ppm"] / 390) : "";
-    }
-    if ($_POST["soduim_me3"] == "ppm") {
-        $na_mehlick3 = (isset($_POST["na_mehlick3_ppm"])) ? ($_POST["na_mehlick3_ppm"] / 230) : "";
-    }
-
-    // Totals for Ratis
-    $c_total = (isset($_POST["c_total"])) ? $_POST["c_total"] : "";
-    $n_total = (isset($_POST["n_total"])) ? $_POST["n_total"] : "";
-    
-    //Create Carbon Nitrogen Ratio if not specified
-    if ($_POST["c_nRatio"] = "") {
-        $c_nRatio = (isset($_POST["c_nRatio"])) ? $_POST["c_nRatio"] : "";
-    } else {
-        $c_nRatio = ( $c_total / $n_total );
-    }
-    
-    //Create CA MG Ratio if not specified
-    if ($_POST["ca_mgRatio"] = "") {
-        $ca_mgRatio = (isset($_POST["ca_mgRatio"])) ? $_POST["ca_mgRatio"] : "";
-    } else {
-        $ca_mgRatio = ( (int)$ca_mehlick3 / (int)$mg_mehlick3 );
-    }
-    
-    
-    //$rand = substr(md5(microtime()),rand(0,26),5);
-    $rand = mt_rand(10000, 99999);
-    
-    
-    // PH lookup table (ph*10 rounded to single decimal point for easy lookup)
-    $phrange = array(
-        30 => [75.0, 11.4],
-        31 => [74.0, 11.2],
-        32 => [73.0, 11.0],
-        33 => [72.0, 10.8],
-        34 => [71.0, 10.6],
-        35 => [70.0, 10.4],
-        36 => [69.0, 10.2],
-        37 => [68.0, 10.0],
-        38 => [67.0, 9.8],
-        39 => [66.0, 9.6],
-        40 => [65.0, 9.4],
-        41 => [63.0, 9.2],
-        42 => [61.0, 9.0],
-        43 => [59.0, 8.8],
-        44 => [57.0, 8.6],
-        45 => [55.0, 8.4],
-        46 => [53.0, 8.2],
-        47 => [51.0, 8.0],
-        48 => [49.0, 7.8],
-        49 => [47.0, 7.6],
-        50 => [45.0, 7.4],
-        51 => [42.0, 7.2],
-        52 => [39.0, 7.0],
-        53 => [36.0, 6.8],
-        54 => [33.0, 6.6],
-        55 => [30.0, 6.4],
-        56 => [27.0, 6.2],
-        57 => [24.0, 6.0],
-        58 => [21.0, 5.8],
-        59 => [18.0, 5.6],
-        60 => [15.0, 5.4],
-        61 => [13.5, 5.3],
-        62 => [12.0, 5.2],
-        63 => [10.5, 5.1],
-        64 => [9.0, 5.0],
-        65 => [7.5, 4.9],
-        66 => [6.0, 4.8],
-        67 => [4.5, 4.7],
-        68 => [3.0, 4.6],
-        69 => [1.5, 4.5],
-        70 => [0.0, 4.4],
-        71 => [0.0, 4.3],
-        72 => [0.0, 4.2],
-        73 => [0.0, 4.1],
-        74 => [0.0, 4.0],
-        75 => [0.0, 3.9],
-        76 => [0.0, 3.8],
-        77 => [0.0, 3.7],
-        78 => [0.0, 3.6],
-        79 => [0.0, 3.5],
-        80 => [0.0, 3.4],
-        81 => [0.0, 3.3],
-        82 => [0.0, 3.2],
-        83 => [0.0, 3.1],
-        84 => [0.0, 3.0],
-        85 => [0.0, 2.9],
-        86 => [0.0, 2.8],
-        87 => [0.0, 2.7],
-        88 => [0.0, 2.6],
-        89 => [0.0, 2.5],
-        90 => [0.0, 2.4],
-        91 => [0.0, 2.3],
-        92 => [0.0, 2.2],
-        93 => [0.0, 2.1],
-        94 => [0.0, 2.0],
-        95 => [0.0, 1.9],
-        96 => [0.0, 1.8],
-        97 => [0.0, 1.7],
-        98 => [0.0, 1.6],
-        99 => [0.0, 1.5],
-        100 => [0.0, 1.4],
-    );
-    
-    /* ********* START ********* */
-    /* ********* ADD BASE SATURATION CALCULATION HERE ********* */
-    
-    // Calculating hydrogen and otherbases
-    $ph = $ph_h2o;      // $ph_h2o from above
-    $aluminium = $al_mehlick3;
-    
-    // round the ph value to single decimal point    
-    $ph_lookup = round($ph, 2); 
-    if ($errorLog = "1") { error_log(print_r("\nph_lookup: " . $ph_lookup . "\nph: " . $ph, true ), 3, "/home/cropmonitor/public_html/site/soilformSubmit-errors.log"); }
-    
-    // lookup Hydrogen and Other Bases
-    $hydrogen = $phrange[($ph_lookup * 10)][0];
-    $otherbases = $phrange[($ph_lookup * 10)][1];
-    $h_rec = round($hydrogen, 2); // recommended level added to DB
-    $ob_rec = round($otherbases, 2); // recommended level added to DB
-    
-    if ($errorLog = "1") { error_log(print_r("\nHydrogen: " . $hydrogen . "\nOther Bases: " . $otherbases, true), 3, "/home/cropmonitor/public_html/site/soilformSubmit-errors.log"); }
-
-    if ( $aluminium < 0 ) { $otherbases = 0; }
-
-    $obresult = 0; //  obresult  == Other Bases Result
-    $hresult = 0; //  hresult   == Hydrogen Result
-    
-    // IF ********************************************************************************
-    if ( $otherbases > 0 ) {
-        while ( (($obresult * 100) / ($cec + $obresult + $hresult) ) <= $otherbases ) {
-            $obresult += 0.001;
-            $tempNo = $obresult;
-            $tempNo1 = $otherbases;
-            $tempNo2 = $hydrogen;
-            // CAUTION: storing value in Calc:E16
-            $hresult = ($tempNo * $tempNo2) / $tempNo1;
-        }
-        $obresult -=  0.001;
-        if ( $hresult != 0 ){
-            $hresult -= 0.001;
-        }
-    } else {
-        while( (($hresult * 100) / $tec) <= $hydrogen ) {
-            $hresultl += 0.001;
-        }
-        $hresult -= 0.001;
-    }
-    if ($errorLog = "1") { error_log(print_r("\nhresult: " . $hresult . "\nobresult: " . $obresult, true), 3, "/home/cropmonitor/public_html/site/soilformSubmit-errors.log"); }
-    
-    // END If ********************************************************************************
-    
-    // Calculating Ca Mg K Na levels based on temp
-    // *** I think that the tecTemp needs to be a sum of $tec and $hresult and $obresult ***
-    // *** As far as I can see on the spreadsheet the TEC in CALC:B16 is "CEC + obresult + CALC:E16"
-    
-    $tecTemp = $cec + $obresult + $hresult;
-    $cecTemp = $cec;
-    $tec = round($tecTemp, 2);
-    $cec = round($cec, 2);
-    if ($errorLog = "1") { error_log(print_r("\ntecTemp: " . $tecTemp . "\ncec: " . $cec . "\ntec: " . $tec, true), 3, "/home/cropmonitor/public_html/site/soilformSubmit-errors.log"); }
-    
-    // CAUTION: for $tecTemp values below 1 and above 100000 this will not work
-    if ( ( 1.0 < $tec  ) && ( 3.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 60.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 20.00;
-        $kbs = $KBS = 5.00;
-        $kbsmax = $KBSMAX = 7.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    elseif ( ( 3.0 < $tec  ) && ( 5.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 62.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 18.00;
-        $kbs = $KBS = 5.00;
-        $kbsmax = $KBSMAX = 7.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    elseif ( ( 5.0 < $tec  ) && ( 7.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 64.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 16.00;
-        $kbs = $KBS = 4.00;
-        $kbsmax = $KBSMAX = 7.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    elseif ( ( 7.0 < $tec  ) && ( 9.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 65.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 15.00;
-        $kbs = $KBS = 4.00;
-        $kbsmax = $KBSMAX = 7.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    elseif ( ( 9.0 < $tec  ) && ( 11.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 67.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 13.00;
-        $kbs = $KBS = 4.00;
-        $kbsmax = $KBSMAX = 7.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    elseif ( ( 11.0 < $tec  ) && ( 30.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 68.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 12.00;
-        $kbs = $KBS = 4.00;
-        $kbsmax = $KBSMAX = 7.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    elseif ( ( 30.0 < $tec  ) && ( 10000.0 >= $tec ) ) {
-        $cabs = $CABS = 0;
-        $cabsmax = $CABSMAX = 70.00;
-        $mgbs = $MGBS = 0;
-        $mgbsmax = $MGBSMAX = 10.00;
-        $kbs = $KBS = 3.00;
-        $kbsmax = $KBSMAX = 6.00; 
-        $nabs = $NABS = 0.50;
-        $nabsmax = $NABSMAX = 1.50; 
-    }
-    
-    // *** CALCULATED TEC % AND PPM MIN / MAX LEVELS ***
-    $cabs_min = $cabs;
-    $ca_ppm_min = ( $tec * $cabs_min * 2 );
-    $cabs_max = $cabsmax;
-    $ca_ppm_max = ( $tec * $cabs_max * 2);
-    $mgbs_min = $mgbs;
-    $mg_ppm_min = ( $tec * $mgbs_min * 1.2 );
-    $mgbs_max = $mgbsmax;
-    $mg_ppm_max = ( $tec * $mgbs_max * 1.2 );
-    $kbs_min = $kbs;
-    $k_ppm_min = ( $tec * $kbs_min * 3.9 );
-    $kbs_max = $kbsmax;
-    $k_ppm_max = ( $tec * $kbs_max * 3.9 );
-    $nabs_min = $nabs;
-    $na_ppm_min = ( $tec * $nabs_min * 2.3 );
-    $nabs_max = $nabsmax;
-    $na_ppm_max = ( $tec * $nabs_max * 2.3 );
-    $albs_min = "0";
-    $al_ppm_min = ( $tec * $albs_min * 0.9 );
-    $albs_max = "0.5";
-    $al_ppm_max = ( $tec * $albs_max * 0.9 );
-    
-    // *** CALCULATED TEC LEVELS ***
-    $cabs_tec = ( $ca_mehlick3 / $tec ) * 100;
-        $cabs_tec = round($cabs_tec, 2);
-    $mgbs_tec = ( $mg_mehlick3 / $tec ) * 100;
-        $mgbs_tec = round($mgbs_tec, 2);
-    $kbs_tec = ( $k_mehlick3 / $tec ) * 100;
-        $kbs_tec = round($kbs_tec, 2);
-    $nabs_tec = ( $na_mehlick3 / $tec ) * 100;
-        $nabs_tec = round($nabs_tec, 2);
-    $albs_tec = ( $al_mehlick3 / $tec ) * 100;
-        $albs_tec = round($albs_tec, 2);
-    
-    // *** CALCULATED PPM FROM MEQ ***
-    $BS_ca_ppm =  $ca_mehlick3 * 200;
-    $BS_mg_ppm =  $mg_mehlick3 * 120;
-    $BS_k_ppm =  $k_mehlick3 * 390;
-    $BS_na_ppm =  $na_mehlick3 * 230;
-    $BS_al_ppm =  $al_mehlick3 * 90;
-    
-    
-    /* ********* ADD BASE SATURATION CALCULATION HERE ********* */
-    /* ********* END ********* */
-    
-    // Check connection
-    if (mysqli_connect_errno()){
-        echo "Failed to connect to MySQL: " . mysqli_connect_error();
-    }
-    		
-    $sql = mysqli_query($con, "INSERT into `soil_records`
-                (
-                    client_records_id,
-                    modx_user_id,
-                    date,
-                    email,
-                    client_name,
-                    site_address,
-                    state_postcode,
-                    analysis_type,
-                    lab_no,
-                    batch_no,
-                    sample_id,
-                    site_id,
-                    crop_type,
-                    soil_type,
-                    date_sampled,
-                    
-                    tec,
-                    cec,
-                    texture,
-                    gravel,
-                    colour,
-                    
-                    NO3_N,
-                    NH3_N,
-                    p_mehlick,
-                    p_bray2,
-                    p_morgan,
-                    k_morgan,
-                    ca_morgan,
-                    mg_morgan,
-                    na_morgan,
-                    ch_h2o,
-                    ocarbon,
-                    omatter,
-                    fe,
-                    ec,
-                    ph_cacl2,
-                    ph_h2o,
-                    paramag,
-                    s_morgan,
-                    b_cacl2,
-                    mn_dtpa,
-                    zn_dtpa,
-                    fe_dtpa,
-                    cu_dtpa,
-                    al,
-                    sl_cacl2,
-                    m_dtpa,
-                    co_dtpa,
-                    se,
-                    
-                    ca_mehlick3,
-    				BS_ca_ppm,
-                    mg_mehlick3,
-    				BS_mg_ppm,
-                    k_mehlick3,
-    				BS_k_ppm,
-                    na_mehlick3,
-    				BS_na_ppm,
-                    al_mehlick3,
-    				BS_al_ppm,
-    				BS_ca2,
-    				BS_mg2,
-    				BS_k,
-    				BS_na,
-    				BS_al3,
-    				BS_ob,
-    				BS_h,
-    				
-    				cabs_min,
-    				ca_ppm_min,
-    				cabs_max,
-    				ca_ppm_max,
-    				mgbs_min,
-    				mg_ppm_min,
-    				mgbs_max,
-    				mg_ppm_max,
-    				kbs_min,
-    				k_ppm_min,
-    				kbs_max,
-    				k_ppm_max,
-    				nabs_min,
-    				na_ppm_min,
-    				nabs_max,
-    				na_ppm_max,
-    				albs_min,
-    				al_ppm_min,
-    				albs_max,
-    				al_ppm_max,
-    				
-    				ob_rec,
-    				h_rec,
-    				
-    				ca_mg_ratio,
-    				
-                    rand
-                ) VALUES (
-                    '{$client_id}',
-                    '{$modx_id}',
-                    '{$date}',
-                    '{$email}',
-                    '{$client_name}',
-                    '{$site_address}',
-                    '{$state_postcode}',
-                    '{$analysis_type}',
-                    '{$lab_no}',
-                    '{$batch_no}',
-                    '{$sample_id}',
-                    '{$site_id}',
-                    '{$crop_type}',
-                    '{$soil_type}',
-                    '{$date_sampled}',
-                    '{$tec}',
-                    '{$cec}',
-                    IF('{$texture}'='',NULL,'{$texture}'),
-                    IF('{$gravel}'='',NULL,'{$gravel}'),
-                    IF('{$colour}'='',NULL,'{$colour}'),
-                    '{$NO3_N}',
-                    '{$NH3_N}',
-                    '{$p_mehlick}',
-                    '{$p_bray2}',
-                    '{$p_morgan}',
-                    '{$k_morgan}',
-                    '{$ca_morgan}',
-                    '{$mg_morgan}',
-                    '{$na_morgan}',
-                    '{$ch_h2o}',
-                    '{$ocarbon}',
-                    '{$omatter}',
-                    '{$fe}',
-                    '{$ec}',
-                    '{$ph_cacl2}',
-                    '{$ph_h2o}',
-                    IF('{$paramag}'='',NULL,'{$paramag}'),
-                    '{$s_morgan}',
-                    '{$b_cacl2}',
-                    '{$mn_dtpa}',
-                    '{$zn_dtpa}',
-                    '{$fe_dtpa}',
-                    '{$cu_dtpa}',
-                    '{$al}',
-                    '{$sl_cacl2}',
-                    '{$m_dtpa}',
-                    '{$co_dtpa}',
-                    '{$se}',
-                    
-                    '{$ca_mehlick3}',
-    				'{$BS_ca_ppm}',
-                    '{$mg_mehlick3}',
-    				'{$BS_mg_ppm}',
-                    '{$k_mehlick3}',
-    				'{$BS_k_ppm}',
-                    '{$na_mehlick3}',
-    				'{$BS_na_ppm}',
-                    '{$al_mehlick3}',	
-    				'{$BS_al_ppm}',
-    				
-    				'{$cabs_tec}',
-    				'{$mgbs_tec}',
-    				'{$kbs_tec}',
-    				'{$nabs_tec}',
-    				'{$aluminium}',
-    				'{$otherbases}',
-    				'{$hydrogen}',
-    
-    				'{$cabs_min}',
-    				'{$ca_ppm_min}',
-    				'{$cabs_max}',
-    				'{$ca_ppm_max}',
-    				'{$mgbs_min}',
-    				'{$mg_ppm_min}',
-    				'{$mgbs_max}',
-    				'{$mg_ppm_max}',
-    				'{$kbs_min}',
-    				'{$k_ppm_min}',
-    				'{$kbs_max}',
-    				'{$k_ppm_max}',
-    				'{$nabs_min}',
-    				'{$na_ppm_min}',
-    				'{$nabs_max}',
-    				'{$na_ppm_max}',
-    				'{$albs_min}',
-    				'{$al_ppm_min}',
-    				'{$albs_max}',
-    				'{$al_ppm_max}',
-    				
-    				'{$ob_rec}',
-    				'{$h_rec}',
-    				
-    				'{$ca_mgRatio}',
-    				
-                    '{$rand}'
-                )" );
-    
-    $insert_id = mysqli_insert_id($con);
-                
-    if ($sql === TRUE) {
-        sleep(10);
-    	// forward to results page if successfully inserts to database  [[~32]]
-    	echo "<script>location.href = '[[~41]]?rand=" . $rand . "&cid=" . $sample_id . "&rid=" . $insert_id . "&stid=" .$crop_type . "';</script>";
-    } else {
-        die(mysqli_error($con)); // TODO: better error handling
-        //echo "User Profile incorrect";
-    }
+/**
+ * soil-submit.php — DEPRECATED
+ *
+ * This file has been superseded by /controllers/soilTestSubmit.php
+ * which uses PDO prepared statements, CSRF protection, and proper auth.
+ *
+ * Any form still pointing here is redirected to the correct controller.
+ * Do not add logic back to this file.
+ */
+
+require_once __DIR__ . '/../../../config/database.php';
+require_once __DIR__ . '/../../../lib/auth.php';
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
 }
 
-<div id="loader-gif" style="z-index:10000;" >[[$plantPOPUP]]</div>
+requireLogin();
 
-<script>
-    $(document).ready(function() {
-        $("#start-loader").click(function() {
-            $("#loader-gif").show();
-                setTimeout(function() {
-                $("#loader-gif").hide();
-            }, 5000);
-        });
-    });
-</script>
+// Redirect POST submissions to the secure controller, preserving POST data
+// is not possible via header redirect — instead show an error so the
+// developer knows this endpoint is stale.
+http_response_code(410);
+echo '<p>This form endpoint is no longer active. '
+   . 'Please update the form action to <code>/controllers/soilTestSubmit.php</code>.</p>';
+exit;

+ 3 - 3
dashboard/crop-analysis/soil-test-data/soil-test-data.php

@@ -15,13 +15,13 @@ $pageTitle = 'Soil Test Analysis Report';
 $siteName = 'Crop Management Platform';
 $activeItem = 'Soil Analysis';
 
-include __DIR__ . '/../../layouts/header.php';
-include __DIR__ . '/../../layouts/navbar.php';
+include __DIR__ . '/../../../layouts/header.php';
+include __DIR__ . '/../../../layouts/navbar.php';
 ?>
 
 <div id="layoutSidenav">
     <div id="layoutSidenav_nav">
-        <?php include __DIR__ . '/../../layouts/sidebar.php'; ?>
+        <?php include __DIR__ . '/../../../layouts/sidebar.php'; ?>
     </div>
     <div id="layoutSidenav_content">
         <main>

+ 36 - 20
layouts/footer.php

@@ -1,31 +1,47 @@
-<!-- jQuery first, then Popper.js, then Bootstrap JS -->
-<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
-<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js" integrity="sha384-eMNCOe7tC1doHpGoWe/6oMVZahOyBRvxQxkjVwPtGPRwO3dRnJgOyR5MwCOgxqA==" crossorigin="anonymous"></script>
-<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
+    </main>
 
-<script type="text/javascript">
-    addEventListener("load", function() { 
-        setTimeout(hideURLbar, 0);
-    }, false);
-    function hideURLbar(){ 
-        window.scrollTo(0,1);
-    }
-</script>
+    <footer class="py-4 bg-light mt-auto">
+        <div class="container-fluid px-4">
+            <div class="d-flex align-items-center justify-content-between small">
+                <div class="text-muted">
+                    <span>&copy; 2003-<?= date('Y') ?> by Crop Monitor</span>. All Rights Reserved
+                </div>
+                <div>
+                    <a href="/privacy-policy.php">Privacy Policy</a>
+                    &middot;
+                    <a href="/terms.php">Terms &amp; Conditions</a>
+                </div>
+            </div>
+        </div>
+    </footer>
+
+</div><!-- /layoutSidenav_content -->
+</div><!-- /layoutSidenav -->
 
-<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.1.0/jquery.magnific-popup.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js"
+        integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
+        crossorigin="anonymous"></script>
 
 <script>
-    window.addEventListener('DOMContentLoaded', event => {
-        const sidebarToggle = document.body.querySelector('#sidebarToggle');
+    window.addEventListener('DOMContentLoaded', () => {
+        // Restore sidebar toggle state from previous visit
+        if (localStorage.getItem('sb|sidebar-toggle') === 'true') {
+            document.body.classList.add('sb-sidenav-toggled');
+        }
+
+        const sidebarToggle = document.querySelector('#sidebarToggle');
         if (sidebarToggle) {
-            sidebarToggle.addEventListener('click', event => {
-                event.preventDefault();
+            sidebarToggle.addEventListener('click', e => {
+                e.preventDefault();
                 document.body.classList.toggle('sb-sidenav-toggled');
-                localStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled'));
+                localStorage.setItem(
+                    'sb|sidebar-toggle',
+                    document.body.classList.contains('sb-sidenav-toggled')
+                );
             });
         }
     });
 </script>
+
 </body>
-</html>
+</html>

+ 60 - 28
layouts/navbar.php

@@ -1,35 +1,67 @@
 <?php
 /**
  * layouts/navbar.php
- * 
- * Reusable top navigation bar.
- * Usage: include __DIR__.'/layouts/navbar.php';
+ *
+ * Top navigation bar — matches original modX sb-topnav output.
+ * Requires lib/auth.php to already be included (for getCurrentUser()).
  */
-$siteName = $siteName ?? 'Crop Management Platform';
-$navItems = $navItems ?? [
-    [ 'href' => '/dashboard/dashboard.php', 'label' => 'Dashboard' ],
-    [ 'href' => '/dashboard/crop-analysis/soil-analysis.php', 'label' => 'Soil Analysis' ],
-    [ 'href' => '/dashboard/crop-analysis/soil-report.php', 'label' => 'Reports' ],
-    [ 'href' => '/login/logout.php', 'label' => 'Logout' ],
-];
-$activeItem = $activeItem ?? '';
+$currentUser = getCurrentUser() ?? ['fullname' => '', 'email' => ''];
+$siteName    = $siteName ?? 'Crop Monitor';
 ?>
-<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
-    <div class="container-fluid">
-        <a class="navbar-brand" href="/"><?= htmlspecialchars($siteName, ENT_QUOTES, 'UTF-8') ?></a>
-        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#topNavbar" aria-controls="topNavbar" aria-expanded="false" aria-label="Toggle navigation">
-            <span class="navbar-toggler-icon"></span>
-        </button>
-        <div class="collapse navbar-collapse" id="topNavbar">
-            <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
-                <?php foreach ($navItems as $item): ?>
-                    <li class="nav-item">
-                        <a class="nav-link<?= ($activeItem === $item['label'] ? ' active' : '') ?>" href="<?= htmlspecialchars($item['href'], ENT_QUOTES, 'UTF-8') ?>">
-                            <?= htmlspecialchars($item['label'], ENT_QUOTES, 'UTF-8') ?>
-                        </a>
-                    </li>
-                <?php endforeach; ?>
+<nav class="sb-topnav navbar navbar-expand-lg navbar-dark bg-success">
+
+    <!-- Brand -->
+    <a class="navbar-brand ps-3 text-white" href="/dashboard/dashboard.php">
+        <?= htmlspecialchars($siteName, ENT_QUOTES, 'UTF-8') ?>
+    </a>
+
+    <!-- Sidebar toggle -->
+    <button type="button" class="btn btn-link btn-sm order-1 order-lg-0 me-4 me-lg-0" id="sidebarToggle" href="#">
+        <i class="fas fa-bars"></i>
+    </button>
+
+    <!-- Right-side user dropdown -->
+    <div class="d-none d-md-inline-block form-inline ms-auto me-0 me-md-3 my-2 my-md-0"></div>
+
+    <ul class="navbar-nav ms-auto ms-md-0 me-3 me-lg-4">
+        <li class="nav-item dropdown">
+            <a class="nav-link dropdown-toggle" id="userDropdown" href="#"
+               role="button" data-bs-toggle="dropdown" aria-expanded="false">
+                <i class="fas fa-user-circle fa-fw"></i>
+                <span class="d-none d-lg-inline text-white small ms-1">
+                    <?= htmlspecialchars($currentUser['fullname'], ENT_QUOTES, 'UTF-8') ?>
+                </span>
+            </a>
+            <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
+                <li>
+                    <a class="dropdown-item fw-bold" href="/dashboard/client-settings/update-details.php">
+                        <?= htmlspecialchars($currentUser['fullname'], ENT_QUOTES, 'UTF-8') ?>
+                    </a>
+                </li>
+                <li>
+                    <a class="dropdown-item" href="/dashboard/client-settings/update-details.php#contact-details">
+                        Edit Profile
+                    </a>
+                </li>
+                <li>
+                    <a class="dropdown-item" href="/login/change-password.php">
+                        Change Password
+                    </a>
+                </li>
+                <li>
+                    <a class="dropdown-item" href="/dashboard/inbox.php">
+                        Inbox
+                    </a>
+                </li>
+                <li><hr class="dropdown-divider"></li>
+                <li>
+                    <a class="dropdown-item" href="/login/logout.php">
+                        <i class="fas fa-sign-out-alt fa-sm fa-fw me-2 text-gray-400"></i>
+                        Logout
+                    </a>
+                </li>
             </ul>
-        </div>
-    </div>
+        </li>
+    </ul>
+
 </nav>

+ 209 - 18
layouts/sidebar.php

@@ -1,25 +1,216 @@
 <?php
 /**
  * layouts/sidebar.php
- * 
- * Reusable sidebar menu for dashboard pages.
- * Usage: include __DIR__.'/layouts/sidebar.php';
+ *
+ * Left sidebar navigation — matches original modX Wayfinder output.
+ * Active state is detected automatically from the current request URI.
+ * Collapsible sections restore open state via Bootstrap accordion.
+ *
+ * Requires lib/auth.php to already be included (for getCurrentUser()).
  */
-$sidebarItems = $sidebarItems ?? [
-    [ 'href' => '/dashboard/dashboard.php', 'label' => 'Home', 'icon' => 'fas fa-home' ],
-    [ 'href' => '/dashboard/crop-analysis/soil-analysis.php', 'label' => 'Soil Analysis', 'icon' => 'fas fa-seedling' ],
-    [ 'href' => '/dashboard/crop-analysis/soil-report.php', 'label' => 'Soil Reports', 'icon' => 'fas fa-file-alt' ],
-    [ 'href' => '/login/change-password.php', 'label' => 'Account', 'icon' => 'fas fa-user-cog' ],
+$currentUser = getCurrentUser() ?? ['fullname' => ''];
+
+// Detect current path for active-link highlighting
+$currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
+
+/**
+ * Return 'active' if $href matches the current path, else ''.
+ */
+$isActive = fn(string $href): string =>
+    str_starts_with($currentPath, $href) ? ' active' : '';
+
+/**
+ * Return 'show' if any child href is active (keeps accordion open on load).
+ */
+$groupActive = function (array $children) use ($currentPath): string {
+    foreach ($children as $child) {
+        if (str_starts_with($currentPath, $child)) return ' show';
+    }
+    return '';
+};
+
+// Child paths per collapsible group — used to keep the right group open
+$weatherChildren   = ['/dashboard/weather/'];
+$cropChildren      = [
+    '/dashboard/crop-analysis/soil-test-data/',
+    '/dashboard/crop-analysis/plant-test-data/',
+    '/dashboard/crop-analysis/water-test-data/',
+    '/dashboard/crop-analysis/animal-dietary-balance/',
+    '/dashboard/crop-analysis/compost-test-data/',
+];
+$settingsChildren  = [
+    '/dashboard/client-settings/soil-recommendations.php',
+    '/dashboard/client-settings/product-list.php',
+    '/dashboard/client-settings/update-details.php',
 ];
-$activeItem = $activeItem ?? '';
 ?>
-<div class="sb-sidenav-menu">
-    <div class="nav">
-        <?php foreach ($sidebarItems as $item): ?>
-            <a class="nav-link<?= ($activeItem === $item['label'] ? ' active' : '') ?>" href="<?= htmlspecialchars($item['href'], ENT_QUOTES, 'UTF-8') ?>">
-                <div class="sb-nav-link-icon"><i class="<?= htmlspecialchars($item['icon'], ENT_QUOTES, 'UTF-8') ?>"></i></div>
-                <?= htmlspecialchars($item['label'], ENT_QUOTES, 'UTF-8') ?>
-            </a>
-        <?php endforeach; ?>
+
+<nav id="sidenavAccordion" class="sb-sidenav accordion sb-sidenav-dark">
+    <div class="sb-sidenav-menu">
+        <div class="nav">
+
+            <!-- Planning Calendar -->
+            <a href="/dashboard/planning-calendar.php"
+               class="nav-link<?= $isActive('/dashboard/planning-calendar.php') ?>">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-map-marker nav_icon"></i>
+                </div>
+                Planning Calendar
+            </a>
+
+            <!-- Report History / Inbox -->
+            <a href="/dashboard/inbox.php"
+               class="nav-link<?= $isActive('/dashboard/inbox.php') ?>">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-inbox nav_icon"></i>
+                </div>
+                Report History
+            </a>
+
+            <!-- Weather (collapsible) -->
+            <a class="nav-link collapsed<?= $groupActive($weatherChildren) ?>"
+               href="#"
+               data-bs-toggle="collapse"
+               data-bs-target="#collapseWeather"
+               aria-expanded="<?= $groupActive($weatherChildren) ? 'true' : 'false' ?>"
+               aria-controls="collapseWeather">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-cloud nav_icon"></i>
+                </div>
+                Weather
+                <div class="sb-sidenav-collapse-arrow">
+                    <i class="fas fa-angle-down"></i>
+                </div>
+            </a>
+            <div class="collapse<?= $groupActive($weatherChildren) ?>"
+                 id="collapseWeather"
+                 data-bs-parent="#sidenavAccordion">
+                <nav class="sb-sidenav-menu-nested nav">
+                    <a class="nav-link<?= $isActive('/dashboard/weather/moisture-sensor-setup.php') ?>"
+                       href="/dashboard/weather/moisture-sensor-setup.php">
+                        <i class="fa fa-eye-dropper nav_icon"></i>&nbsp;Moisture Sensor Setup
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/weather/weather-monitoring.php') ?>"
+                       href="/dashboard/weather/weather-monitoring.php">
+                        <i class="fas fa-cloud-sun nav_icon"></i>&nbsp;Weather Monitoring
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/weather/moisture-monitoring.php') ?>"
+                       href="/dashboard/weather/moisture-monitoring.php">
+                        <i class="fas fa-tint nav_icon"></i>&nbsp;Moisture Monitoring
+                    </a>
+                </nav>
+            </div>
+
+            <!-- Pesticide -->
+            <a href="/dashboard/pesticide.php"
+               class="nav-link<?= $isActive('/dashboard/pesticide.php') ?>">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-bug nav_icon"></i>
+                </div>
+                Pesticide
+            </a>
+
+            <!-- Crop Analysis (collapsible) -->
+            <a class="nav-link collapsed<?= $groupActive($cropChildren) ?>"
+               href="#"
+               data-bs-toggle="collapse"
+               data-bs-target="#collapseCropAnalysis"
+               aria-expanded="<?= $groupActive($cropChildren) ? 'true' : 'false' ?>"
+               aria-controls="collapseCropAnalysis">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-tree nav_icon"></i>
+                </div>
+                Crop Analysis
+                <div class="sb-sidenav-collapse-arrow">
+                    <i class="fas fa-angle-down"></i>
+                </div>
+            </a>
+            <div class="collapse<?= $groupActive($cropChildren) ?>"
+                 id="collapseCropAnalysis"
+                 data-bs-parent="#sidenavAccordion">
+                <nav class="sb-sidenav-menu-nested nav">
+                    <a class="nav-link<?= $isActive('/dashboard/crop-analysis/soil-test-data/') ?>"
+                       href="/dashboard/crop-analysis/soil-test-data/soil-test-data.php">
+                        <i class="fas fa-globe-asia nav_icon"></i>&nbsp;Soil Test Data
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/crop-analysis/plant-test-data/') ?>"
+                       href="/dashboard/crop-analysis/plant-test-data/">
+                        <i class="fab fa-pagelines nav_icon"></i>&nbsp;Plant Test Data
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/crop-analysis/water-test-data/') ?>"
+                       href="/dashboard/crop-analysis/water-test-data/">
+                        <i class="fa fa-tint nav_icon"></i>&nbsp;Water Test Data
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/crop-analysis/animal-dietary-balance/') ?>"
+                       href="/dashboard/crop-analysis/animal-dietary-balance/">
+                        <i class="fas fa-dog nav_icon"></i>&nbsp;Animal Dietary Balance
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/crop-analysis/compost-test-data/') ?>"
+                       href="/dashboard/crop-analysis/compost-test-data/">
+                        <i class="fas fa-cloud nav_icon"></i>&nbsp;Compost Test Data
+                    </a>
+                </nav>
+            </div>
+
+            <!-- Irrigation Controller -->
+            <a href="/dashboard/irrigation/"
+               class="nav-link<?= $isActive('/dashboard/irrigation/') ?>">
+                <div class="sb-nav-link-icon">
+                    <i class="fas fa-cloud-sun-rain nav_icon"></i>
+                </div>
+                Irrigation Controller
+            </a>
+
+            <!-- Client Settings (collapsible) -->
+            <a class="nav-link collapsed<?= $groupActive($settingsChildren) ?>"
+               href="#"
+               data-bs-toggle="collapse"
+               data-bs-target="#collapseSettings"
+               aria-expanded="<?= $groupActive($settingsChildren) ? 'true' : 'false' ?>"
+               aria-controls="collapseSettings">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-cog nav_icon"></i>
+                </div>
+                Client Settings
+                <div class="sb-sidenav-collapse-arrow">
+                    <i class="fas fa-angle-down"></i>
+                </div>
+            </a>
+            <div class="collapse<?= $groupActive($settingsChildren) ?>"
+                 id="collapseSettings"
+                 data-bs-parent="#sidenavAccordion">
+                <nav class="sb-sidenav-menu-nested nav">
+                    <a class="nav-link<?= $isActive('/dashboard/client-settings/soil-recommendations.php') ?>"
+                       href="/dashboard/client-settings/soil-recommendations.php">
+                        <i class="fa fa-cog nav_icon"></i>&nbsp;Soil Recommendations
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/client-settings/product-list.php') ?>"
+                       href="/dashboard/client-settings/product-list.php">
+                        <i class="fa fa-cog nav_icon"></i>&nbsp;Product List
+                    </a>
+                    <a class="nav-link<?= $isActive('/dashboard/client-settings/update-details.php') ?>"
+                       href="/dashboard/client-settings/update-details.php">
+                        <i class="fa fa-cog nav_icon"></i>&nbsp;Update Details
+                    </a>
+                </nav>
+            </div>
+
+            <!-- Crop Cards -->
+            <a href="/dashboard/crop-cards/"
+               class="nav-link<?= $isActive('/dashboard/crop-cards/') ?>">
+                <div class="sb-nav-link-icon">
+                    <i class="fa fa-tree nav_icon"></i>
+                </div>
+                Crop Cards
+            </a>
+
+        </div>
+    </div>
+
+    <!-- Footer: logged-in user -->
+    <div class="sb-sidenav-footer">
+        <div class="small">Logged in as:</div>
+        <?= htmlspecialchars($currentUser['fullname'], ENT_QUOTES, 'UTF-8') ?>
     </div>
-</div>
+
+</nav>

+ 0 - 131
newClientDetails.php

@@ -1,131 +0,0 @@
-<script type="text/javascript">
-    $(function(){
-
-        $('#email').click(function(){
-            $('#newClient').modal('show');
-            return false;
-        })
-
-    });
-</script>
-
-<!-- Modal -->
-<div class="modal fade" id="newClient" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display: block;">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
-                <h2 class="modal-title">Add New Client</h2>
-            </div>
-            <div class="modal-body">
-                <form method="post" action="" id="newClientDetails" >
-
-                    <input type="hidden" class="form-control" name="m_user" id="m_user" value="1" required>
-                    <input type="hidden" class="form-control" name="modx_user_attributes" id="modx_user_attributes" value="1" required>
-
-                    <div class="form-group">
-                        <label for="name">Name:</label>
-                        <input type="text" class="form-control" name="Nname" placeholder="Client Name" id="Nname" required >
-                    </div>
-                    <div class="form-group">
-                        <label for="company">Company:</label>
-                        <input type="text" class="form-control" name="Ncompany" placeholder="Company Name" id="Ncompany"  >
-                    </div>
-                    <div class="form-group">
-                        <label for="email">Email address</label>
-                        <input type="email" class="form-control" name="Nemail" placeholder="Email address" required id="Nemail"  >
-                    </div>
-                    <div class="form-group">
-                        <label for="email">Mobile Number</label>
-                        <input type="text" class="form-control" name="Nmobile" placeholder="" id="Nmobile"  >
-                    </div>
-                    <div class="form-group">
-                        <label for="email">Phone Number</label>
-                        <input type="text" class="form-control" name="Nphone" placeholder="" id="Nphone" value="[[+Nphone]]" >
-                    </div>
-                    <div class="form-group">
-                        <label for="email">Fax Number</label>
-                        <input type="text" class="form-control" name="Nfax" placeholder="" id="Nfax" >
-                    </div>
-                    <hr>
-                    <div class="form-group">
-                        <label for="address">Address:</label>
-                        <input type="text" class="form-control" name="Naddress" placeholder="Address" required id="Naddress"  >
-                    </div>
-                    <div class="form-group">
-                        <label for="state">Town / State:</label>
-                        <input type="text" class="form-control" name="Nstate" placeholder="Town, State, Postcode" required id="Nstate"  >
-                    </div>
-                </form>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
-                <button form="newClientDetails" class="btn btn-primary" type="Nsubmit" name="NCsubmit" value="NCsubmit">Save changes</button>
-            </div>
-        </div><!-- /.modal-content -->
-    </div><!-- /.modal-dialog -->
-</div>
-
-<?php
-error_reporting(E_ALL);
-ini_set('display_errors', 1);
-
-$sql = null;
-$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-
-
-//Get figures
-if(isset($_POST['NCsubmit'])){ //check if form was submitted
-    $modx_id = (isset($_POST["m_user"])) ? $_POST["m_user"] : "";
-    $modx_user_attributes = (isset($_POST["modx_user_attributes"])) ? $_POST["modx_user_attributes"] : "";
-    $company = (isset($_POST["Ncompany"])) ? $_POST["Ncompany"] : "";
-    $client = (isset($_POST["Nname"])) ? $_POST["Nname"] : "";
-    $address = (isset($_POST["Naddress"])) ? $_POST["Naddress"] : "";
-    $postcode = (isset($_POST["Nstate"])) ? $_POST["Nstate"] : "";
-    $email = (isset($_POST["Nemail"])) ? $_POST["Nemail"] : "";
-    $mobile = (isset($_POST["Nmobile"])) ? $_POST["Nmobile"] : "";
-    $phone = (isset($_POST["Nmobile"])) ? $_POST["Nmobile"] : "";
-    $fax = (isset($_POST["Nfax"])) ? $_POST["Nfax"] : "";
-
-
-    // Check connection
-    if (mysqli_connect_errno())
-    {
-        echo "Failed to connect to MySQL: " . mysqli_connect_error();
-    }
-
-    $sql = mysqli_query($con, "INSERT into `client_records`
-            (
-                modx_user_id,
-                modx_user_attributes,
-                company,
-                client,
-                address,
-                state_postcode,
-                email,
-                phone,
-                mobile,
-                fax
-            ) VALUES (
-                '" . $modx_id . "',
-                '" . $modx_user_attributes . "',
-                '" . $company . "',
-                '" . $client . "',
-                '" . $address . "',
-                '" . $postcode . "',
-                '" . $email . "',
-                '" . $phone . "',
-                '" . $mobile . "',
-                '" . $fax . "'
-            )" );
-
-    if ($sql === TRUE)
-    {
-        echo "<div class='form-group has-success'><input type='text' class='form-control1' id='inputSuccess1'>Success!</div>";
-        echo "<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>";
-    } else {
-        die(mysqli_error($con)); // TODO: better error handling
-        echo "<div class='form-group has-error'><input type='text' class='form-control1' id='inputError1'>Error</div>";
-    }
-}
-?>

+ 0 - 170
post.php

@@ -1,170 +0,0 @@
-<?php
-//$modx_user = $modx->user->get('id');
-$modx_user = 1;
-
-$con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-// Check connection
-if (mysqli_connect_errno()) {
-    echo "Failed to connect to MySQL: " . mysqli_connect_error();
-}
-$result = mysqli_query($con, "SELECT * FROM `client_records` Where `modx_user_id` = $modx_user ");
-// mysqli_query returns false if something went wrong with the query
-
-if ($result === FALSE) {
-    die(mysqli_error($con)); // TODO: better error handling
-} else {
-?>
-<div class='col-md-12 form-group'>
-    <label for='client_id'>Current Client</label><?php
-    //$modx_user = $modx->user->get('id');
-    $modx_user = 1;
-
-    $result = mysqli_query($con, "SELECT * FROM `client_records` Where `modx_user_id` = $modx_user ");
-
-    // mysqli_query returns false if something went wrong with the query
-
-    if ($result === FALSE) {
-        die(mysqli_error($con)); // TODO: better error handling
-    } else {
-    ?>
-    <div class='col-md-12 form-group'>
-        <label for='client_id'>Current Client</label>
-        <div><select name='client_id' id='client_id' class='form-control1' onChange='Choice();'>
-            <option>Select current client or add new client below...</option>
-            <?php
-        while ($row=mysqli_fetch_array($result)){
-            ?>
-            <option value="<?php echo $row['id']; ?>" id="<?php echo $row['id']; ?>"><?php echo $row['id'] . " - " . $row['client'] . " - " . $row['company']; ?></option>
-            <?php
-        }
-            ?>
-
-            </select></div>
-    </div>
-    <?php
-    }
-    ?>
-
-
-
-    <script type="text/javascript">
-        <?php
-    $index = 0;
-    while ($row = mysqli_fetch_array($result))
-    {
-        ?>
-        var email[<?php echo $index; ?>] = <?php echo $row['email']; ?>;
-        var name[<?php echo $index; ?>] = <?php echo $row['name']; ?>;
-        var company[<?php echo $index; ?>] = <?php echo $row['company']; ?>;
-        var site_address[<?php echo $index; ?>] = <?php echo $row['site_address']; ?>;
-        var state_postcode[<?php echo $index; ?>] = <?php echo $row['state_postcode']; ?>;
-            <?php
-        $index++;
-    }
-            ?>
-    </script>
-
-    <?php
-    mysqli_close($con);
-    ?>
-
-    <script type="text/javascript">
-        function Choice() {
-            y = document.getElementById("client_id");
-
-            document.getElementById("email").value = email[y.selectedIndex];
-            document.getElementById("name").value = name[y.selectedIndex];
-            document.getElementById("company").value = company[y.selectedIndex];
-            document.getElementById("site_address").value = site_address[y.selectedIndex];
-            document.getElementById("state_postcode").value = state_postcode[y.selectedIndex];
-        }
-    </script>
-
-    <div class="col-md-6 form-group">
-        <label for="email">Email address<span class="error">*</span></label>
-        <input type="email" class="form-control" name="email" id="email" value="" required autocomplete="on">
-    </div>
-    <div class="col-md-6 form-group">
-        <label for="client_name">Client Name<span class="error">*</span></label>
-        <input type="text" class="form-control" name="name" id="name" value="" required autocomplete="on">
-    </div>
-    <div class="col-md-6 form-group">
-        <label for="company_name">Company Name</label>
-        <input type="text" class="form-control" name="company" id="company" value="" autocomplete="on">
-    </div>
-    <div class="col-md-6 form-group">
-        <label for="site_address">Site Address</label>
-        <input type="text" class="form-control" name="site_address" id="site_address" value="" autocomplete="on">
-    </div>
-    <div class="col-md-6 form-group">
-        <label for="state_postcode">State & Postcode</label>
-        <input type="text" class="form-control" name="state_postcode" id="state_postcode" value="" autocomplete="on">
-    </div>
-    <div><select name='client_id' id='client_id' class='form-control1' onChange='Choice();'>
-        <option>Select current client or add new client below...</option>
-        <?php
-    while ($row=mysqli_fetch_array($result)){
-        ?>
-        <option value="<?php echo $row['id']; ?>" id="<?php echo $row['id']; ?>"><?php echo $row['id'] . " - " . $row['client'] . " - " . $row['company']; ?></option>
-        <?php
-    }
-        ?>
-
-        </select></div>
-</div>
-<?php
-}
-?>
-<script type="text/javascript">
-    <?php
-    $index = 0;
-    while ($row = mysqli_fetch_array($result))
-    {
-    ?>
-    var email[<?php echo $index; ?>] = <?php echo $row['email']; ?>;
-    var name[<?php echo $index; ?>] = <?php echo $row['name']; ?>;
-    var company[<?php echo $index; ?>] = <?php echo $row['company']; ?>;
-    var site_address[<?php echo $index; ?>] = <?php echo $row['site_address']; ?>;
-    var state_postcode[<?php echo $index; ?>] = <?php echo $row['state_postcode']; ?>;
-        <?php
-        $index++;
-    }
-        ?>
-</script>
-
-<?php
-mysqli_close($con);
-?>
-
-<script type="text/javascript">
-    function Choice() {
-        y = document.getElementById("client_id");
-
-        document.getElementById("email").value = email[y.selectedIndex];
-        document.getElementById("name").value = name[y.selectedIndex];
-        document.getElementById("company").value = company[y.selectedIndex];
-        document.getElementById("site_address").value = site_address[y.selectedIndex];
-        document.getElementById("state_postcode").value = state_postcode[y.selectedIndex];
-    }
-</script>
-
-<div class="col-md-6 form-group">
-    <label for="email">Email address<span class="error">*</span></label>
-    <input type="email" class="form-control" name="email" id="email" value="" required autocomplete="on">
-</div>
-<div class="col-md-6 form-group">
-    <label for="client_name">Client Name<span class="error">*</span></label>
-    <input type="text" class="form-control" name="name" id="name" value="" required autocomplete="on">
-</div>
-<div class="col-md-6 form-group">
-    <label for="company_name">Company Name</label>
-    <input type="text" class="form-control" name="company" id="company" value="" autocomplete="on">
-</div>
-<div class="col-md-6 form-group">
-    <label for="site_address">Site Address</label>
-    <input type="text" class="form-control" name="site_address" id="site_address" value="" autocomplete="on">
-</div>
-<div class="col-md-6 form-group">
-    <label for="state_postcode">State & Postcode</label>
-    <input type="text" class="form-control" name="state_postcode" id="state_postcode" value="" autocomplete="on">
-</div>

+ 0 - 65
soilAnalysisCalcs.php

@@ -1,65 +0,0 @@
-<?php
-error_reporting(E_ALL);
-ini_set('display_errors', 1);
-
-$id = $_GET['id'];
-?>
-
-<!DOCTYPE HTML>
-<html lang="en-US">
-    <head>
-        <meta charset="utf-8">
-        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-        <meta http-equiv="refresh" content="600">
-        <title>Job Tracker</title>
-        <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
-
-        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
-        <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
-        <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
-
-        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
-        <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
-        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
-        <script type="text/javascript" src="https://use.fontawesome.com/1e2844bb90.js"></script>
-        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" integrity="sha256-T0Vest3yCU7pafRw9r+settMBX6JkKN06dqBnpQ8d30=" crossorigin="anonymous"></script>
-
-    </head>
-
-    <body>
-
-        <div class="container">
-
-            <div class="row">
-                <div class="col">
-
-
-                    <?php
-                    $con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-
-                    $result = mysqli_query($con, " SELECT * FROM `soil_records` WHERE `id` = $id ");
-
-                    if (!$result) {
-                        printf("Error: %s\n", mysqli_error($con));
-                        exit();
-                    }
-
-                    while ($row = mysqli_fetch_assoc($result)) {
-
-                        echo "<div>";
-                        print "<pre>";
-                        print_r($row);
-                        print "<pre>";
-                        echo "</div>";
-
-                    } ?>
-
-                </div>
-            </div>
-
-        </div>
-
-
-    </body>
-</html>

+ 0 - 821
test-analysis.php

@@ -1,821 +0,0 @@
-<?php
-error_reporting(E_ALL);
-ini_set('display_errors', 1);
-
-$sql = null;
-$con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-
-//set todays date
-$date = date("Y-m-d H:i:s");
-
-//Get figures
-$email = "ben@tazz.com.au";
-$client_name = "Benjamin Harris";
-$site_address = "24 Alfred Street";
-$state_postcode = "";
-$analysis_type = "Soil Test";  //for future types of Soil Analysis
-$lab_no = "NT2698/3";
-$batch_no = "3";
-$sample_id = "Sample 3";
-$site_id = "";
-$crop_type = "Grape";
-$soil_type = "sandy";  //need to fix form to say soil_type not analysis_type
-$date_sampled = "2018/11/22";
-$tec = "50.2";
-$cec = "45.4";
-$texture = "Clay Loam";
-$gravel = "";
-$colour = "Black";
-$NO3_N = "2.6";
-$NH3_N = "5.3";
-$p_mehlick = "36";
-$p_bray2 = "0";
-$p_morgan = "4.1";
-$k_morgan = "154";
-$ca_morgan = "4174";
-$mg_morgan = "1347";
-$na_morgan = "0";
-$ch_h2o = "62";
-$ocarbon = "3.95";
-$omatter = ($ocarbon * 2.7);
-$fe = "0";
-$ec = "0.097";
-$ph_cacl2 = "";
-$ph_h2o = "6.4";
-$paramag = "6000";
-$s_morgan = "";
-$b_cacl2 = "1.24";
-$mn_dtpa = "40";
-$zn_dtpa = "9.5";
-$fe_dtpa = "156";
-$cu_dtpa = "7.6";
-$al = "0";
-$sl_cacl2 = "0";
-$m_dtpa = "0";
-$co_dtpa = "0";
-$se = "0";
-$ca_mehlick3 = "30.28";
-$mg_mehlick3 = "14.01";
-$k_mehlick3 = "0.76";
-$na_mehlick3 = "0.38";
-$al_mehlick3 = "0.24";
-
-$c_total = "4.5";
-$n_total = ($NO3_N + $NH3_N);
-$c_nRatio = ($c_total / $n_total);
-$ca_mgRatio = ($ca_mehlick3 / $mg_mehlick3);
-
-//$rand = substr(md5(microtime()),rand(0,26),5);
-$rand = mt_rand(10000, 99999);
-
-
-// PH lookup table (ph*10 rounded to single decimal point for easy lookup)
-$phrange = array(
-    30 => [75.0, 11.4],
-    31 => [74.0, 11.2],
-    32 => [73.0, 11.0],
-    33 => [72.0, 10.8],
-    34 => [71.0, 10.6],
-    35 => [70.0, 10.4],
-    36 => [69.0, 10.2],
-    37 => [68.0, 10.0],
-    38 => [67.0, 9.8],
-    39 => [66.0, 9.6],
-    40 => [65.0, 9.4],
-    41 => [63.0, 9.2],
-    42 => [61.0, 9.0],
-    43 => [59.0, 8.8],
-    44 => [57.0, 8.6],
-    45 => [55.0, 8.4],
-    46 => [53.0, 8.2],
-    47 => [51.0, 8.0],
-    48 => [49.0, 7.8],
-    49 => [47.0, 7.6],
-    50 => [45.0, 7.4],
-    51 => [42.0, 7.2],
-    52 => [39.0, 7.0],
-    53 => [36.0, 6.8],
-    54 => [33.0, 6.6],
-    55 => [30.0, 6.4],
-    56 => [27.0, 6.2],
-    57 => [24.0, 6.0],
-    58 => [21.0, 5.8],
-    59 => [18.0, 5.6],
-    60 => [15.0, 5.4],
-    61 => [13.5, 5.3],
-    62 => [12.0, 5.2],
-    63 => [10.5, 5.1],
-    64 => [9.0, 5.0],
-    65 => [7.5, 4.9],
-    66 => [6.0, 4.8],
-    67 => [4.5, 4.7],
-    68 => [3.0, 4.6],
-    69 => [1.5, 4.5],
-    70 => [0.0, 4.4],
-    71 => [0.0, 4.3],
-    72 => [0.0, 4.2],
-    73 => [0.0, 4.1],
-    74 => [0.0, 4.0],
-    75 => [0.0, 3.9],
-    76 => [0.0, 3.8],
-    77 => [0.0, 3.7],
-    78 => [0.0, 3.6],
-    79 => [0.0, 3.5],
-    80 => [0.0, 3.4],
-    81 => [0.0, 3.3],
-    82 => [0.0, 3.2],
-    83 => [0.0, 3.1],
-    84 => [0.0, 3.0],
-    85 => [0.0, 2.9],
-    86 => [0.0, 2.8],
-    87 => [0.0, 2.7],
-    88 => [0.0, 2.6],
-    89 => [0.0, 2.5],
-    90 => [0.0, 2.4],
-    91 => [0.0, 2.3],
-    92 => [0.0, 2.2],
-    93 => [0.0, 2.1],
-    94 => [0.0, 2.0],
-    95 => [0.0, 1.9],
-    96 => [0.0, 1.8],
-    97 => [0.0, 1.7],
-    98 => [0.0, 1.6],
-    99 => [0.0, 1.5],
-    100 => [0.0, 1.4],
-);
-
-
-
-/* ********* START ********* */
-/* ********* ADD BASE SATURATION CALCULATION HERE ********* */
-
-// ***
-//  calculating hydrogen and otherbases
-// ***
-
-$ph = $ph_h2o;      // $ph_h2o from above
-$aluminium = $al;   // VERIFY: assuming $al is aluminium
-
-// round the ph value to single decimal point    
-$ph_lookup = round($ph, 1); 
-
-// lookup H and Other Bases
-$hydrogen = $phrange[($ph_lookup * 10)][0];
-$other_Bases = $phrange[($ph_lookup * 10)][1];
-
-// CAUTION: $otherbases & other_Bases are too similar variable names, prone to error
-$otherbases = $other_Bases;
-
-// CAUTION: $otherbases & $otherBases can be different variables depending on aluminum levels.
-if ( $aluminium < 0 ) {
-    $otherbases = 0;
-}
-
-// INTEGRATE: in the spreadsheet at this point the macro sets the value of hydrogen into a cell
-// there is no comparable variable here...  don't know if the cell gets used again...
-
-// *** the hydrogen value that is entered into the cell is the final Hydrogen value, which is then just written to the database ***
-
-$hbs = $hydrogen;
-
-//
-//  obresult
-//
-
-
-$obresult = 0;  // INTEGRATE: starting at zero per spreadsheet, double check that this is intended
-
-if ( $otherbases > 0 ) {
-    while ( ($obresult * 100 / $tec) <= $otherbases ) {
-        $obresult += 0.001;
-        $tempNo = $obresult;
-        $tempNo1 = $otherbases;
-        $tempNo2 = $hydrogen;
-        // CAUTION: storing value in Calc:E16
-        $obresult_offset_1_0_cell = $tempNo * $tempNo2 / $tempNo1;
-    }
-    $obresult -= 0.001;
-    if ( $obresult_offset_1_0_cell != 0 ){
-        $obresult_offset_1_0_cell -= 0.001;
-    }
-}
-else {
-
-    // ERROR: VALUE OF CELL Calc:E16 IS BEING READ PRIOR TO ASSIGNMENT!! 
-    // THIS COULD BE USING LEFT OVER DATA FROM PREVIOUS RUNS! THE CURRENT VALUE IS 0.
-    $obresult_offset_1_0_cell = 0; // INTEGRATE: NEEDS VALUE ASSIGNED
-
-    while( ($obresult_offset_1_0_cell * 100 / $tec) <= $hydrogen ) {
-        $obresult_offset_1_0_cell += 0.001;
-    }
-    $obresult_offset_1_0_cell -= 0.001;
-}
-
-
-//
-// Calculating Ca Mg K Na levels based on temp
-//
-// *** I think that the tecTemp needs to be a sum of $tec and $obresult_offset_1_0_cell and $obresult ***
-// *** As far as I can see on the spreadsheet the TEC in CALC:B16 is "CEC + obresult + CALC:E16"
-//$tecTemp = $obresult_offset_1_0_cell;    
-$tecTemp = $cec + $obresult + $obresult_offset_1_0_cell;
-$tec = $tecTemp;
-
-// CAUTION: for $tecTemp values below 1 and above 100000 this will not work
-
-if ( ( 1.0 < $tecTemp  ) && ( $tecTemp >= 3.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 60.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 20.00;
-    $kbs = $KBS = 5.00;
-    $kbsmax = $KBSMAX = 7.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-elseif ( ( 3.0 < $tecTemp  ) && ( $tecTemp >= 5.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 62.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 18.00;
-    $kbs = $KBS = 5.00;
-    $kbsmax = $KBSMAX = 7.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-elseif ( ( 5.0 < $tecTemp  ) && ( $tecTemp >= 7.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 64.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 16.00;
-    $kbs = $KBS = 4.00;
-    $kbsmax = $KBSMAX = 7.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-elseif ( ( 7.0 < $tecTemp  ) && ( $tecTemp >= 9.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 65.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 15.00;
-    $kbs = $KBS = 4.00;
-    $kbsmax = $KBSMAX = 7.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-elseif ( ( 9.0 < $tecTemp  ) && ( $tecTemp >= 11.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 67.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 13.00;
-    $kbs = $KBS = 4.00;
-    $kbsmax = $KBSMAX = 7.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-elseif ( ( 11.0 < $tecTemp  ) && ( $tecTemp >= 30.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 68.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 12.00;
-    $kbs = $KBS = 4.00;
-    $kbsmax = $KBSMAX = 7.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-elseif ( ( 30.0 < $tecTemp  ) && ( $tecTemp >= 100000.0 ) ) {
-    $cabs = $CABS = 0;
-    $cabsmax = $CABSMAX = 70.00;
-    $mgbs = $MGBS = 0;
-    $mgbsmax = $MGBSMAX = 10.00;
-    $kbs = $KBS = 3.00;
-    $kbsmax = $KBSMAX = 6.00; 
-    $nabs = $NABS = 0.50;
-    $nabsmax = $NABSMAX = 1.50; 
-}
-
-// *** CALCULATED TEC MIN / MAX LEVELS
-$cabs_min = $cabs;
-$cabs_max = $cabsmax;
-$mgbs_min = $mgbs;
-$mgbs_max = $mgbsmax;
-$kbs_min = $kbs;
-$kbs_max = $kbsmax;
-$nabs_min = $nabs;
-$nabs_max = $nabsmax;
-$albs_min = "0";
-$albs_max = "0.5";
-
-// *** CALCULATED TEC LEVELS
-$cabs_tec = $ca_mehlick3 * $tec * 100;
-$mgbs_tec = $mg_mehlick3 * $tec * 100;
-$kbs_tec = $k_mehlick3 * $tec * 100;
-$nabs_tec = $na_mehlick3 * $tec * 100;
-$albs_tec = $al_mehlick3 * $tec * 100;
-
-// *** CALCULATED PPM FROM MEQ
-$BS_ca_ppm =  $ca_mehlick3 * 200;
-$BS_mg_ppm =  $mg_mehlick3 * 120;
-$BS_k_ppm =  $k_mehlick3 * 390;
-$BS_na_ppm =  $na_mehlick3 * 230;
-$BS_al_ppm =  $al_mehlick3 * 90;
-
-
-/* ********* ADD BASE SATURATION CALCULATION HERE ********* */
-/* ********* END ********* */
-
-/*
-NOTES:
-will need to add rows in mysql to save data that has been calculated above.
-
-
-*/
-
-// Check connection
-if (mysqli_connect_errno())
-{
-    echo "Failed to connect to MySQL: " . mysqli_connect_error();
-}
-
-$sql = mysqli_query($con, "INSERT into `soil_records`
-            (
-                date,
-                email,
-                client_name,
-                site_address,
-                state_postcode,
-                analysis_type,
-                lab_no,
-                batch_no,
-                sample_id,
-                site_id,
-                crop_type,
-                soil_type,
-                date_sampled,
-                tec,
-                cec,
-                texture,
-                gravel,
-                colour,
-                NO3_N,
-                NH3_N,
-                p_mehlick,
-                p_bray2,
-                p_morgan,
-                k_morgan,
-                ca_morgan,
-                mg_morgan,
-                na_morgan,
-                ch_h2o,
-                ocarbon,
-                omatter,
-                fe,
-                ec,
-                ph_cacl2,
-                ph_h2o,
-                paramag,
-                s_morgan,
-                b_cacl2,
-                mn_dtpa,
-                zn_dtpa,
-                fe_dtpa,
-                cu_dtpa,
-                al,
-                sl_cacl2,
-                m_dtpa,
-                co_dtpa,
-                se,
-
-                ca_mehlick3,
-				BS_ca_ppm,
-                mg_mehlick3,
-				BS_mg_ppm,
-                k_mehlick3,
-				BS_k_ppm,
-                na_mehlick3,
-				BS_na_ppm,
-                al_mehlick3,
-				BS_al_ppm,
-				BS_ca2,
-				BS_mg2,
-				BS_k,
-				BS_na,
-				BS_al3,
-				BS_h,
-
-				cabs_min,
-				cabs_max,
-				mgbs_min,
-				mgbs_max,
-				kbs_min,
-				kbs_max,
-				nabs_min,
-				nabs_max,
-				albs_min,
-				albs_max,
-
-				ca_mg_ratio,
-
-                rand
-            ) VALUES (
-                '" . $date . "',
-                '" . $email . "',
-                '" . $client_name . "',
-                '" . $site_address . "',
-                '" . $state_postcode . "',
-                '" . $analysis_type . "',
-                '" . $lab_no . "',
-                '" . $batch_no . "',
-                '" . $sample_id . "',
-                '" . $site_id . "',
-                '" . $crop_type . "',
-                '" . $soil_type . "',
-                '" . $date_sampled . "',
-                '" . $tec . "',
-                '" . $cec . "',
-                IF('" . $texture . "'='',NULL,'" . $texture . "'),
-                IF('" . $gravel . "'='',NULL,'" . $gravel . "'),
-                IF('" . $colour . "'='',NULL,'" . $colour . "'),
-                '" . $NO3_N . "',
-                '" . $NH3_N . "',
-                '" . $p_mehlick . "',
-                '" . $p_bray2 . "',
-                '" . $p_morgan . "',
-                '" . $k_morgan . "',
-                '" . $ca_morgan . "',
-                '" . $mg_morgan . "',
-                '" . $na_morgan . "',
-                '" . $ch_h2o . "',
-                '" . $ocarbon . "',
-                '" . $omatter . "',
-                '" . $fe . "',
-                '" . $ec . "',
-                '" . $ph_cacl2 . "',
-                '" . $ph_h2o . "',
-                IF('" . $paramag . "'='',NULL,'" . $paramag . "'),
-                '" . $s_morgan . "',
-                '" . $b_cacl2 . "',
-                '" . $mn_dtpa . "',
-                '" . $zn_dtpa . "',
-                '" . $fe_dtpa . "',
-                '" . $cu_dtpa . "',
-                '" . $al . "',
-                '" . $sl_cacl2 . "',
-                '" . $m_dtpa . "',
-                '" . $co_dtpa . "',
-                '" . $se . "',
-
-                '" . $ca_mehlick3 . "',
-				'" . $BS_ca_ppm . "',
-                '" . $mg_mehlick3 . "',
-				'" . $BS_mg_ppm . "',
-                '" . $k_mehlick3 . "',
-				'" . $BS_k_ppm . "',
-                '" . $na_mehlick3 . "',
-				'" . $BS_na_ppm . "',
-                '" . $al_mehlick3 . "',	
-				'" . $BS_al_ppm . "',
-
-				'" . $cabs_tec . "',
-				'" . $mgbs_tec . "',
-				'" . $kbs_tec . "',
-				'" . $nabs_tec . "',
-				'" . $aluminium . "',
-				'" . $hbs . "',
-
-				'" . $cabs_min . "',
-				'" . $cabs_max . "',
-				'" . $mgbs_min . "',
-				'" . $mgbs_max . "',
-				'" . $kbs_min . "',
-				'" . $kbs_max . "',
-				'" . $nabs_min . "',
-				'" . $nabs_max . "',
-				'" . $albs_min . "',
-				'" . $albs_max . "',
-
-				'" . $ca_mgRatio . "',
-
-                '" . $rand . "'
-            )" );
-
-$insert_id = mysqli_insert_id($con);
-
-/*            
-if ($sql === TRUE)
-	{
-	//echo "success"; //CHECKING
-	// forward to results page if successfully inserts to database
-	echo "<script>location.href = '[[~32]]?rand=" . $rand . "&cid=" . $sample_id . "&rid=" . $insert_id . "&stid=" .$crop_type . "';</script>";
-    } else {
-    die(mysqli_error($con)); // TODO: better error handling
-    //echo "User Profile incorrect";
-}
-*/
-?>
-
-<table style="width:50%">
-    <tr>
-        <th style="width:25%">Element</th>
-        <th style="width:75%">Results</th> 
-    </tr>
-
-    <tr>
-        <td> Date </td>
-        <td> <?php echo $date; ?> </td>
-    </tr>
-
-    <tr>
-        <td> Email </td>
-        <td> <?php echo $email; ?> </td>
-    </tr>
-    <tr>
-        <td> Client </td>
-        <td> <?php echo $client_name; ?> </td>
-    </tr>
-    <tr>
-        <td> Address </td>
-        <td> <?php echo $site_address; ?> </td>
-    </tr>
-    <tr>
-        <td> State </td>
-        <td> <?php echo $state_postcode; ?> </td>
-    </tr>
-    <tr>
-        <td> Analysis </td>
-        <td> <?php echo $analysis_type; ?> </td>
-    </tr>
-    <tr>
-        <td> Lab # </td>
-        <td> <?php echo $lab_no; ?> </td>
-    </tr>
-    <tr>
-        <td> Batch </td>
-        <td> <?php echo $batch_no; ?> </td>
-    </tr>
-    <tr>
-        <td> Sample ID </td>
-        <td> <?php echo $sample_id; ?> </td>
-    </tr>
-    <tr>
-        <td> Site ID </td>
-        <td> <?php echo $site_id; ?> </td>
-    </tr>
-    <tr>
-        <td> Crop Type </td> 
-        <td> <?php echo $crop_type; ?> </td>
-    </tr>
-    <tr>
-        <td> Soil Type </td> 
-        <td> <?php echo $soil_type; ?> </td>
-    </tr>
-    <tr>
-        <td> Date Sampled </td> 
-        <td> <?php echo $date_sampled; ?> </td>
-    </tr>
-
-    <tr>
-        <td> TEC </td> 
-        <td> <?php echo $tecTemp; ?> </td>
-    </tr>
-    <tr>
-        <td> CEC </td> 
-        <td> <?php echo $cec; ?> </td>
-    </tr>
-    <tr>
-        <td> Texture </td> 
-        <td> <?php echo $texture; ?> </td>
-    </tr>
-    <tr>
-        <td> Gravel </td> 
-        <td> <?php echo $gravel; ?> </td>
-    </tr>
-    <tr>
-        <td> Colour </td> 
-        <td> <?php echo $colour; ?> </td>
-    </tr>
-    <tr>
-        <td> N03_Nitrogen </td> 
-        <td> <?php echo $NO3_N; ?> </td>
-    </tr>
-    <tr>
-        <td> NH3_Nitrogen </td> 
-        <td> <?php echo $NH3_N; ?> </td>
-    </tr>
-    <tr>
-        <td> P Mehlick </td> 
-        <td> <?php echo $p_mehlick; ?> </td>
-    </tr>
-    <tr>
-        <td> P Bray2</td> 
-        <td> <?php echo $p_bray2; ?> </td>
-    </tr>
-    <tr>
-        <td> P Morgan</td> 
-        <td> <?php echo $p_morgan; ?> </td>
-    </tr>
-    <tr>
-        <td> K Morgan</td> 
-        <td> <?php echo $k_morgan; ?> </td>
-    </tr>
-    <tr>
-        <td> Ca Morgan</td> 
-        <td> <?php echo $ca_morgan; ?> </td>
-    </tr>
-    <tr>
-        <td> Mg Morgan</td> 
-        <td> <?php echo $mg_morgan; ?> </td>
-    </tr>
-    <tr>
-        <td> Na Morgan</td> 
-        <td> <?php echo $na_morgan; ?> </td>
-    </tr>
-    <tr>
-        <td> Chloride</td> 
-        <td> <?php echo $ch_h2o; ?> </td>
-    </tr>
-    <tr>
-        <td> Organic Carbon</td> 
-        <td> <?php echo $ocarbon; ?> </td>
-    </tr>
-    <tr>
-        <td> Organic Matter</td> 
-        <td> <?php echo $omatter; ?> </td>
-    </tr>
-    <tr>
-        <td> Iron</td> 
-        <td> <?php echo $fe; ?> </td>
-    </tr>
-    <tr>
-        <td> EC</td> 
-        <td> <?php echo $ec; ?> </td>
-    </tr>
-    <tr>
-        <td> ph cacl2</td> 
-        <td> <?php echo $ph_cacl2; ?> </td>
-    </tr>
-    <tr>
-        <td> ph h2o</td> 
-        <td> <?php echo $ph_h2o; ?> </td>
-    </tr>
-    <tr>
-        <td> Parameg</td> 
-        <td> <?php echo $paramag; ?> </td>
-    </tr>
-
-    <tr>
-        <td> Sulphur</td> 
-        <td> <?php echo $s_morgan; ?> </td>
-    </tr>
-    <tr>
-        <td> Boron</td> 
-        <td> <?php echo $b_cacl2; ?> </td>
-    </tr>
-    <tr>
-        <td> Mananese</td> 
-        <td> <?php echo $mn_dtpa; ?> </td>
-    </tr>
-    <tr>
-        <td> Zinc</td> 
-        <td> <?php echo $zn_dtpa; ?> </td>
-    </tr>
-    <tr>
-        <td> Iron</td> 
-        <td> <?php echo $fe_dtpa; ?> </td>
-    </tr>
-    <tr>
-        <td> Copper</td> 
-        <td> <?php echo $cu_dtpa; ?> </td>
-    </tr>
-    <tr>
-        <td> Aluminium</td> 
-        <td> <?php echo $al; ?> </td>
-    </tr>
-    <tr>
-        <td> Silicoln</td> 
-        <td> <?php echo $sl_cacl2; ?> </td>
-    </tr>
-    <tr>
-        <td> Moly</td> 
-        <td> <?php echo $m_dtpa; ?> </td>
-    </tr>
-    <tr>
-        <td> Colbalt</td> 
-        <td> <?php echo $co_dtpa; ?> </td>
-    </tr>
-    <tr>
-        <td> Selenium</td> 
-        <td> <?php echo $se; ?> </td>
-    </tr>
-
-    <tr>
-        <td> Ca</td> 
-        <td> <?php echo $ca_mehlick3; ?> </td>
-    </tr>
-    <tr>
-        <td> Ca ppm</td> 
-        <td> <?php echo $BS_ca_ppm; ?> </td>
-    </tr>
-    <tr>
-        <td> Mg</td> 
-        <td> <?php echo $mg_mehlick3; ?> </td>
-    </tr>
-    <tr>
-        <td> Mg ppm</td> 
-        <td> <?php echo $BS_mg_ppm; ?> </td>
-    </tr>
-    <tr>
-        <td> K</td> 
-        <td> <?php echo $k_mehlick3; ?> </td>
-    </tr>
-    <tr>
-        <td> K ppm</td> 
-        <td> <?php echo $BS_k_ppm; ?> </td>
-    </tr>
-    <tr>
-        <td> Na</td> 
-        <td> <?php echo $na_mehlick3; ?> </td>
-    </tr>
-    <tr>
-        <td> Na ppm</td> 
-        <td> <?php echo $BS_na_ppm; ?> </td>
-    </tr>
-    <tr>
-        <td> Al</td> 
-        <td> <?php echo $al_mehlick3; ?> </td>
-    </tr>
-    <tr>
-        <td> Al ppm</td> 
-        <td> <?php echo $BS_al_ppm; ?> </td>
-    </tr>
-
-    <tr>
-        <td> CA</td> 
-        <td> <?php echo $cabs_tec; ?> </td>
-    </tr>
-    <tr>
-        <td> MG</td> 
-        <td> <?php echo $mgbs_tec; ?> </td>
-    </tr>
-    <tr>
-        <td> K</td> 
-        <td> <?php echo $kbs_tec; ?> </td>
-    </tr>
-    <tr>
-        <td> NA</td> 
-        <td> <?php echo $nabs_tec; ?> </td>
-    </tr>
-    <tr>
-        <td> AL</td> 
-        <td> <?php echo $aluminium; ?> </td>
-    </tr>
-    <tr>
-        <td> H</td> 
-        <td> <?php echo $hbs; ?> </td></tr>
-
-    <tr>
-        <td> CA_min</td>
-        <td> <?php echo $cabs_min; ?> </td>
-    </tr>
-    <tr>
-        <td> CA_max</td> 
-        <td> <?php echo $cabs_max; ?> </td>
-    </tr>
-    <tr>
-        <td> MG_min</td> 
-        <td> <?php echo $mgbs_min; ?> </td>
-    </tr>
-    <tr>
-        <td> MG_max</td> 
-        <td> <?php echo $mgbs_max; ?> </td>
-    </tr>
-    <tr>
-        <td> K_min</td> 
-        <td> <?php echo $kbs_min; ?> </td>
-    </tr>
-    <tr>
-        <td> K_max</td> 
-        <td> <?php echo $kbs_max; ?> </td>
-    </tr>
-    <tr>
-        <td> NA_min</td> 
-        <td> <?php echo $nabs_min; ?> </td>
-    </tr>
-    <tr>
-        <td> NA_max</td> 
-        <td> <?php echo $nabs_max; ?> </td>
-    </tr>
-    <tr>
-        <td> AL_min</td> 
-        <td> <?php echo $albs_min; ?> </td>
-    </tr>
-    <tr>
-        <td> AL_max</td> 
-        <td> <?php echo $albs_max; ?> </td>
-    </tr>
-
-    <tr>
-        <td> Rand #</td> 
-        <td> <?php echo $rand; ?> </td>
-    </tr>
-</table>