Script (Klasse) um dauerhaft Variablen bzw. Arrays zu speichern

Hallo zusammen,

da ich doch einiges an Scripten mittlerweile habe und ich teilweise vor dem Problem stehe, Daten oder auch Arrays dauerhaft zu speichern (also nicht in einer Variablen) habe ich eine kleine Klasse erstellt, die jede beliebige Daten oder auch gesamte Arrays in der Datenbank speichern kann.

Am besten die Klasse in ein eigenes Script reinpacken, diesem einen fixen namen geben: settings.ips.php


<?
/* Settings Class 2013-01-27--------------------------------------------------
	Klasse zum Speichern von Werten in der Datenbank abhängig vom Script

	Beispiel:

	Einbindung in Script:
	require_once "settings.ips.php";
	$set = new settings();
	
	Schreiben:
	$set->SetValue([NAME], [WERT], [INSTANZ])

	Lesen:
	$set->GetValue([NAME], [INSTANZ])

	Löschen:
	$set->DeleteValue([NAME], [INSTANZ])

	[NAME]:    Name der Einstellung (Stringfeld, max. 25 Stellen)
	[WERT]:    Wert der zur Einstellung gespeichert werden soll (
	           String oder Array, max 28kb)
	[INSTANZ]: InstanzID zu der die Einstellung gehört. Wird nichts angegeben, wird
				  die Instanz ID aus $_IPS["SELF"] ermittelt

	Alle Daten anzeigen (HTML Tabelle):
	echo $set->ShowEntries(); // Rückgabe STRING(HTML Tabelle)

	ChangeLog:__________________________________________________________________
	Version 1.0 : Initial
	Version 1.1 : Now with Arrays
	Version 1.2 : DeleteValue added
	Version 1.3 : File Path adjusted, delete with % supported
	
*/
 class settings {
	// Falls es Probleme mit dem Pfad gibt, bitte ggf. anpassen. bzw. das user (ip-symcon\user) Verzeichnis erstellen!!!!
	var $CONF_DB = "../user/settings.sqlite";
	var $DBH = "";
	function __construct(){
		$this->CONF_DB = __DIR__ . "/".$this->CONF_DB;
		// Verzeichnis ggf. erstellen
		@mkdir(dirname($this->CONF_DB));
		$this->initDB();
	}
	
	public function destroyDB(){

		$this->DBH = null;
		unlink($this->CONF_DB);
	}
	
   private function initDB() {
		   $this->DBH = new PDO("sqlite:".$this->CONF_DB);
		   $sql = "CREATE TABLE IF NOT EXISTS settings
			        (id       INTEGER PRIMARY KEY,
						instance INTEGER,
						name     CHAR(25),
			         value    TEXT,
						array    INTEGER,
						changed  INTEGER)";
			$res = $this->DBH->query($sql);
			$this->checkdberr();
    }
    
    private function checkDBErr(){
		  $error = $this->DBH->errorInfo();
		  if($error[0] != "" & $error[0] != "00000") {
		      print "<p>DATABASE CONNECTION ERROR:</p>";
		      print_r($error);
		      die;
		  } else {
		   return true;
		  }
    }
    
	 public function setValue($name, $value, $instance = 0){
		$instance = intval($instance);
		if($instance == 0) $instance = $_IPS['SELF'];
		if(intval($instance) == 0) die("Settings SetValue: No Instance given or 0
");
		if(empty($name)) die("Settings SetValue: No Name of attribute given, Abort. 
");

		// Alten Eintrag oder Enträge löschen
		$sql = "SELECT count(*) as anz FROM settings WHERE instance=$instance AND name='$name'";
		$res = $this->DBH->query($sql);
		$row = $res->fetch();
		$rowcount = $row["anz"];
	   // Single Einträg in Value
  		if(is_array($value)){
		  	$value = serialize($value); // Serialisieren für Arrays
			$arr=1;
		} else {
		   $arr = 0;
		}
		if(strlen($value) > (1024*28))die("Settings SetValue: value to big!
");
		if($rowcount > 1 || $rowcount == 0){
			$sql = "DELETE FROM settings WHERE instance=$instance AND name='$name'";
     		$this->DBH->exec($sql);
     		$sql = "INSERT INTO settings (instance, name, value, changed, array) VALUES (
     		         $instance, '$name', '$value', ".time().", $arr)";

		} else {
		   // get ID and update
			$sql = "SELECT * FROM settings WHERE instance=$instance AND name='$name'";
			$res = $this->DBH->query($sql);
			$row = $res->fetch();
		   $id = $row["id"];
		   $sql = "UPDATE settings set instance=$instance, name='$name', value='$value',
			                            changed=".time().", array=$arr WHERE id=$id";
		}
      $this->DBH->exec($sql);
      $this->checkDBErr();

			
	 }
	 
	 public function getValue($name, $instance = 0, $time = false){
		$instance = intval($instance);
		if($instance == 0) $instance = $_IPS['SELF'];
		if(intval($instance) == 0) die("Settings SetValue: No Instance given or 0
");
		if(empty($name)) die("Settings SetValue: No Name of attribute given, Abort. 
");

		// Alten Eintrag oder Enträge löschen
		$sql = "SELECT * FROM settings WHERE instance=$instance AND name='$name' ORDER by instance, name";
		$res = $this->DBH->query($sql);
		$this->checkDBErr();
		
		$count = 0;
		foreach($res as $row){
			if($row["array"] == 1){
			   return unserialize($row["value"]);
			} else {
				if($time){ // Mit Zeitrückgabe
               return Array("VALUE" => $row["value"], "LASTUPDATE"=>$row["changed"]);
				}else{
               return $row["value"];
				}
			}
		}
		if($count == 0){
			return false;
		}
	}
	public function getValueTime($name, $instance = 0){
	   return $this->getValue($name, $instance, true);
	}


 public function DeleteValue($name, $instance = 0){
		$instance = intval($instance);
		if($instance == 0) $instance = $_IPS['SELF'];
		if(intval($instance) == 0) die("Settings SetValue: No Instance given or 0
");
		if(empty($name)) die("Settings SetValue: No Name of attribute given, Abort. 
");

		// Alten Eintrag oder Enträge löschen
		$sql = "DELETE FROM settings WHERE instance=$instance AND name LIKE '$name'";
      $this->DBH->exec($sql);
      return $this->checkDBErr();
 }
	
 public function ShowEntries(){
		$sql = "SELECT * FROM settings ORDER by instance, name";
		$res = $this->DBH->query($sql);
		$this->checkDBErr();

		$count = 0;
		$output = "<table border=1>";
		$output .= "<thead><tr><td>Instance</td><td>Name</td></td><td>Value</td><td>Is Array</td><td>Last Update</td></tr></thead>";
		foreach($res as $row){
		   $output .="<tr>";
			$output .=" <td>".@IPS_GetName(intval($row["instance"])).", (".$row["instance"].")</td>
							<td>".$row["name"]."</td>
							<td>".$row["value"]."</td>
							<td>".$row["array"]."</td>
							<td>".date("d.m.Y, H:i",$row["changed"])."</td>
						 ";
  		   $output .="</tr>";
		}
  		$output .= "</table>";
  		return $output;
	}
}


?>

Und hier ein Beispiel für die Verwendung im eigenen Script:


<?php
  require_once("settings.ips.php");
  $set = new settings;
  
  //Etwas speichern:
  $set->SetValue("STATUS", 1);

 //Etwas lesen:
  echo $set->GetValue("STATUS");

 //oder auch ganze Arrays:
 $arr["A"] = Array("NAME"=>"Mustermann", "ALTER" => 40);
 $arr["B"] = Array("NAME"=>"Mustermax", "ALTER" => 10);

 // Speichern
 $set->SetValue("PERSONEN", $arr);

 // Lesen:
 print_r($set->GetValue("PERSONEN"));

?>

Prinzipiell werden Die Daten zum aktuellen Script gespeichert dh. Sind Skriptspezifisch, Man kann aber auch einen 3. Parameter mitgeben, wo man einen Identifier (zb. instanz ID) mitgibt, dann kann auch von untersch. Skripten darauf zugegriffen werden.

Dies kann benutzt werden um diverse Informationen in Skripten dauerhaft zu speichern und beim späteren Aufruf wieder zu lesen.
Technisch wird das ganze in einer kleinen SQLITE DB abgelegt.

Die Inhalte der DB kann man anezigen lassen mit folgendem Script:


<?
 require_once("settings.ips.php");
 $set = new settings;
 echo $set->ShowEntries();
?>

Anwendungsmöglichkeiten:

  • Wenn man einen Schalter mehrfach drückt, dann kann man die ‚Counts‘ im Script mitzählen
  • Bei einem Wartungsscript kann man letzte Abfragen von Variablen / Instanzen mitspeichern
  • Interne technische Variablen etc.

Hier muss man nicht immer extra Variablen anlegen für Variablen / Zustände die nicht direkt in IPS verwendet werden sollen (WebFront etc).

Update:

GGf. müsst Ihr in der PHP.INI im IPS Verzeichnis noch die Extension für SQLITE aktivieren.
Dazu ggf. folgende zwei Zeilen in die PHP.INI im IPS Verzeichnis einfügen und sicherstellen dass die dlls im ext Verzeichnis liegen.

extension = php_pdo_sqlite.dll
extension = php_sqlite3.dlll

sehr geil danke :slight_smile:

Das finde ich sehr gut.
Das sollten wir in die Script Library Sammlung mit aufnehmen.

Danke für die Blumen :slight_smile:

Habe gerade oben noch einen Neue Version eingepflegt. Man kann jetzt auch einen Eintrag wieder löschen:

Funktion: DeleteValue

Im Beispiel sind falsche Functions für das Schreiben drin.

In der Class heißt es SetValue und im Beispiel SaveValue.

Solltest Du mal abändern.

Und noch eine Anmerkung.

Der Pfad zur DB muss absolut angeben werden, sonst klappt es bei mir nicht.

var $CONF_DB = "c:/ip-symcon2/webfront/user/settings.sqlite";
IPS_GetKernelDir()

in Verbindung mit der Klasse bringt leider einen Fehler. Denke aber eher das das ein Problem mit PHP ist.

danke. hab’s geändert.

Müsste mit der neuen Version jetzt gehen.
Habe gerade aktualisiert.

Wo finde ich eigentlich die zwei DLL`s ? php_pdo_sqlite.dll + php_sqlite3.dlll

Wenn ich im Netz suche komme ich auf jede Menge Seiten bei denen man besser nichts downloaded :frowning:

Du kannst Dir auf php.net die passende PHP Version für Windows runterladen, diese entzippen und die dlls aus dieser nehmen.

Also auf der PHP.NET Seite liegt die Vers. 5.4.11 …

Mein Logfile sagt aber das IPS 5.4.4 braucht und für die Vers. finde ich die DLL nicht. Any Idea ??

28.01.2013 18:28:17.189 | 0 | MESSAGE | ScriptEngine | >Erweiterung php_pdo_sqlite.dll nicht geladen. Version stimmt nicht überein: PHP: 5.4.4, EXT: 5.4.11
28.01.2013 18:28:17.236 | 0 | MESSAGE | ScriptEngine | >Erweiterung: php_soap.dll
28.01.2013 18:28:17.282 | 0 | MESSAGE | ScriptEngine | >Erweiterung php_sqlite3.dll nicht geladen. Version stimmt nicht überein: PHP: 5.4.4, EXT: 5.4.11
2

Hallo BestEx.

Hier wirst Du fündig.

http://www.ip-symcon.de/forum/threads/20750-Z-Wave-Batterie-Instanzen-Module-automatisch-optimieren?p=188095#post188095

Gruß
Lutz

Herzlichen Dank, der Link hat mir sehr geholfen und eine Menge Zeit gespart

Irgendwie stehe ich auf dem Schlauch :frowning:
Wenn ich das Test Script laufen lasse :

<?
  require_once("settings.ips.php");
  $set = new settings;

  //Etwas speichern:
  $set->SetValue("STATUS", 1);

 //Etwas lesen:
  echo $set->GetValue("STATUS");

 //oder auch ganze Arrays:
 $arr["A"] = Array("NAME"=>"Mustermann", "ALTER" => 40);
 $arr["B"] = Array("NAME"=>"Mustermax", "ALTER" => 10);

 // Speichern
 $set->SetValue("PERSONEN", $arr);

 // Lesen:
 print_r($set->GetValue("PERSONEN"));

?>

Erhalte ich die folgende Fehlermeldung :

Fatal error:  Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [14] unable to open database file' in C:\IP-Symcon\scripts\settings.ips.php:51
Stack trace:
#0 C:\IP-Symcon\scripts\settings.ips.php(51): PDO->__construct('sqlite:C:\IP-Sy...')
#1 C:\IP-Symcon\scripts\settings.ips.php(41): settings->initDB()
#2 C:\IP-Symcon\scripts\27951.ips.php(3): settings->__construct()
#3 {main}
  thrown in C:\IP-Symcon\scripts\settings.ips.php on line 51
Abort Processing during Fatal-Error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [14] unable to open database file' in C:\IP-Symcon\scripts\settings.ips.php:51
Stack trace:
#0 C:\IP-Symcon\scripts\settings.ips.php(51): PDO->__construct('sqlite:C:\IP-Sy...')
#1 C:\IP-Symcon\scripts\settings.ips.php(41): settings->initDB()
#2 C:\IP-Symcon\scripts\27951.ips.php(3): settings->__construct()
#3 {main}
  thrown
   Error in Script C:\IP-Symcon\scripts\settings.ips.php on Line 51

Nur um sicher zu gehen das hier kein Missverständnis vorliegt. Ich gehe davon aus das nur die dll`s in das ext. Directory kopiert werden. Das Logfile sagt ja auch das die Dinger geladen werden.
Ich muss also keine weiteren Komponenten installieren insbesondere auch keine SQL Installation machen, Richtig ???

Nein musst du nicht.
Also du musst die notwendigen dlls pdo für sqlite und sqlite 3 im ext verzeichnis haben, die php.ini anpassen, dann sollte es gehen.

ggf. mal mit einem script nochmals prüfen ob PDO SQLITE und SQLITE3 auch geladen ist

<?php
phpinfo();
?>

ah sorry,

hast du die letzte Version( 1. Post in diesem Thread ) die DLLS scheinen korrekt zu sein.
Allerdings hat er probleme das DB File anzulegen.
Bitte probiere die neue Version oben mit der absoluten Pfadangabe.

Ich habe mir das gerade mal angeschaut und die 2 Dll`s wurden geladen und sind enabled. Daran kann es also nicht liegen. Aber laut Fehlermeldung

SQLSTATE[HY000] [14] unable to open database file

kann die Kiste eine Datenbank nicht öffnen

Hast Du die aktuelle Version im 1. post verwendet. Es liegt an der Pfadangabe der sqlite DB.
Diese habe ich in der letzten Version auf absolut umgestellt, da es wohl bei einigen Usern Probleme machte.

Ich habe gerade nochmal das aktuelle script drüber kopiert. Leider ist der Fehler der gleiche :frowning:
Das ist die Fehlermeldung :

Fatal error: Uncaught exception ‚PDOException‘ with message ‚SQLSTATE[HY000] [14] unable to open database file‘ in C:\IP-Symcon\scripts\settings.ips.php:51

und das steht in Zeile 51 des settings scripts :

       $this-&gt;DBH = new PDO("sqlite:".$this-&gt;CONF_DB);