[Gelöst] Generelles Problem mit SAS WebGUI-Mehrfachnutzung

Die Struktur des Cache-Arrays auf die Datenbank zu übertragen hat einen Vor- und auch einen großen Nachteil. Der Vorteil ist ganz klar das gezielte Schreiben von einzelnen Informationen in die Datenbank, der Nachteil ist die Beschneidung des Pseudos V##, da damit der Benutzer keine flüchtigen eigenen Variablen mehr on the Fly generieren kann, ohne dass die Datenbankstruktur ständig angepasst werden müsste.

Ich möchte ja die Datenbank nur dazu benutzen, um Zugriffsprobleme zu umgehen, nicht um eine Datenbank aufzubauen. ;)

Trotzdem überlege ich gerade, halt auch immer die Datenbankstruktur on the fly anzupassen, wobei ich nicht weiß, wie sich das auf die Performance auswirkt. Datenbankaufrufe sind nicht gerade die schnellsten.


gezielt - sequentiell -> haben übrigens nichts miteinander zu tun.

da wirfst du was durcheinander.
sequentiell heißt aufeinanderfolgendes Lesen/Schreiben
random oder wahlfrei meinst du wohl, wenn man gezielt einen Datensatz ansprechen möchte.

Noch ein Problem ist die Fritzbox. Muss testen, ob es da überhaupt werkelt. Auf dem Pi musste ich nachinstallieren.
 
Für SaS und meinen SNOMs nutze ich das über php-cgi auf der Fritz!Box.

Also Struktur...
PHP:
$db->exec("CREATE TABLE cache (id INTEGER PRIMARY KEY,daten VARCHAR(999999999))");

Erster Datensatz...
PHP:
$insert=$db->prepare("INSERT INTO cache (`daten`) VALUES (:daten)");
Der hat die id 1
...wobei ich nicht erkennen kann was :daten sind.

Du willst den Cache so holen...
PHP:
$select=$db->query("SELECT `daten` FROM `cache`");

Skeptisch ich bin, denn den ersten Datensatz ich nehmen würde (id 1).
Beispiel...
PHP:
$sth = $dbh->prepare('SELECT daten FROM cache WHERE id = 1'); // Ersten Datensatz mit id==1 holen

Und dann immer auf diese id (Datensatz) arbeiten...
PHP:
$count = $dbh->exec("UPDATE cache SET daten = 'wieder viel text' WHERE id = 1");
$sth = $dbh->prepare('SELECT daten FROM cache WHERE id = 1');
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
// Update steht jetzt in der Tabelle und $Status['daten']

Viele viele viele viele Datensätze machen SQLite3 Datenbanken langsam.
Für SaS brauchst du so höchstens 3 Datensätze.
1. Vielleicht als Standardcache, falls was schiefläuft
2. Arbeitscache, wird also dauernd benutzt
3. Ein Backupdatensatz der von Zeit zu Zeit aktualisiert wird
...fertig

Aber erstmal reicht 1 Datensatz zum eigentlichen Problem.
 
Zuletzt bearbeitet:
Habe mal getestet: Fritzbox mit sas-Standardinstallation werkelt mit sqlite ohne zusätzliche Veränderung, das passt. Fürs Pi habe ich es angepasst ( apt-get install apache2 php5 libapache2-mod-php5 php5-curl php5-imap php5-sqlite ), läuft auch. Jetzt bastel ich bei Gelegenheit die Alpha-Version.
 
SQLite3 ist schon cool, hoffentlich funktioniert das auch so.
Alles weiss ich natürlich nicht darüber.
Da gibt es noch so viel mehr...

Da brauchste dir nur mal die sqlite_master der Fritz!Box NAS Datenbank angucken.
Die gibt es in...
/tmp/fritznasdb_main.db3
und
/var/media/NEW_LINK/FRITZ/mediabox/fritznasdb_part.db3
...kannst du dir mit master.php angucken.
(In db.php den Pfad/Datenbank eintragen)

...es gibt auch sogenannte "Trigger"...aber :noidea::silly::gruebel:
 
Zuletzt bearbeitet:
Funktioniert nicht. Irgendwas stimmt nicht. Es werden plötzlich 2 Datensätze angelegt. Ein kompletter von sasap und ein Murks von sas, obwohl sie die gleiche Funktion benutzen.

schau dir bitte die Funktionen an. Es soll nur EIN Datenbanksatz erzeugt werden. Achja, bitte nur innerhalb der Funktion ändern, bitte kein include oder sonstwas dazupacken.

PHP:
function getSASCache() {
/********************/
	global $GerListARR;
	global $GerARRDat;
	
	$datenbank=$GerARRDat."alle";
	if (!file_exists($datenbank)) {
		$db=new PDO('sqlite:'.$datenbank);
		$db->exec("CREATE TABLE cache (id INTEGER PRIMARY KEY,daten VARCHAR(999999999))");
		if (!is_writable($datenbank)) {
			chmod($datenbank, 0777);
		}
		$insert=$db->prepare("INSERT INTO cache (`daten`) VALUES (:daten)");
		$insert->bindValue(':daten', "");
		$insert->execute();
	}
	else {
		$db=new PDO('sqlite:'.$datenbank);
	}
	$select=$db->query("SELECT `daten` FROM `cache` WHERE id = 1");
	$datenout=$select->fetchAll(PDO::FETCH_ASSOC);
	$GerListARR=unserialize($datenout[0]["daten"]);
}
	
	
function putSASCache() {
/********************/
	global $GerListARR;
	global $GerARRDat;
	
	$daten=serialize($GerListARR);
	$datenbank=$GerARRDat."alle";
	if (!file_exists($datenbank)) {
		$db=new PDO('sqlite:'.$datenbank);
		$db->exec("CREATE TABLE cache (id INTEGER PRIMARY KEY,daten VARCHAR(999999999))");
		if (!is_writable($datenbank)) {
			chmod($datenbank, 0777);
		}
		$insert=$db->prepare("INSERT INTO cache (`daten`) VALUES (:daten)");
		$insert->bindValue(':daten', "");
		$insert->execute();
	}
	else {
		$db=new PDO('sqlite:'.$datenbank);
	}

	$update=$db-> prepare("UPDATE `cache` SET `daten` = :daten WHERE id = 1");
	$update->bindValue(':daten', $daten);
	$update->execute();
}

Nachtrag: Wenn sasap schreibt, ist alles ok. Ein Datensatz und gut ists. sas liest auch diesen Datensatz. Aber wehe sas schreibt, dann sind plötzlich zwei Datensätze vorhanden. Der erste verstümmelt und der Zweite wieder komplett. Wo ist mein Fehler im Script? :bahnhof:
 
Zuletzt bearbeitet:
Ich verstehe nicht warum du nach links geneigte Hochkommata verwendest.
$select=$db->query("SELECT `daten` FROM `cache` WHERE id = 1");

Entweder, innerhalb von Gänsefüßchen Oben, einfache Hochkommata, oder bei richtiger Schreibweise, keine.
$select=$db->query("SELECT daten FROM cache WHERE id = 1");

Dann rate ich dir anstatt nur CREATE zu benutzen zu dieser Form...
exec
("CREATE TABLE IF NOT EXISTS cache (id INTEGER PRIMARY KEY, daten VARCHAR(65335))");


Formsache: Du öffnest immer die Datenbank ohne das sie explizit geschlossen wurde.
So würde ich das eben nicht machen.
Sie kann auch ohne Probleme die ganze Zeit "offen" sein, einfach mal testen, ohne: $db=new PDO('sqlite:'.$datenbank);
...b.z.w. einmal reicht, wirklich. ;)

Ansonsten: $db = null; // schliesst die Datenbank (Handle)
 
Zuletzt bearbeitet:
Könntest du das oben mal einbauen, nicht dass ich da was übersehe. Bin inzwischen richtig betriebsblind von dem Code. :mad:
 
Verflixte LINUX-Rechteverwaltung!!!!!!!! DAS war wieder mal das Problem!!!! sas als www-data und sasap als root. :(
Kaum händisch die Rechte der Datenbank auf 0777 und schon läuft es.....
 
Nun, trotzdem...

Nach meinem Verständnis (ungetestet) sieht eine "Korrektur" so aus...
PHP:
 function getSASCache() {
/********************/
    global $GerListARR;
    global $GerARRDat;
    
    $datenbank=$GerARRDat."alle";
    if (!file_exists($datenbank)) {
        $db=new PDO('sqlite:'.$datenbank);
        $db->exec("CREATE TABLE IF NOT EXISTS cache (id INTEGER PRIMARY KEY,daten VARCHAR(999999999))");
        if (!is_writable($datenbank)) {
            chmod($datenbank, 0777);
        }
        $insert=$db->prepare("INSERT INTO cache (daten) VALUES (':daten')");
        $insert->bindValue(':daten', "");
        $insert->execute();
    }
    else {
        $db=new PDO('sqlite:'.$datenbank);
    }
    $select=$db->query("SELECT daten FROM cache WHERE id = 1");
    $datenout=$select->fetchAll(PDO::FETCH_ASSOC);
    $GerListARR=unserialize($datenout[daten]["daten"]);
}
    
    
function putSASCache() {
/********************/
    global $GerListARR;
    global $GerARRDat;
    
    $daten=serialize($GerListARR);
    $datenbank=$GerARRDat."alle";
    if (!file_exists($datenbank)) {
        $db=new PDO('sqlite:'.$datenbank);
        $db->exec("CREATE TABLE IF NOT EXISTS cache (id INTEGER PRIMARY KEY,daten VARCHAR(999999999))");
        if (!is_writable($datenbank)) {
            chmod($datenbank, 0777);
        }
        $insert=$db->prepare("INSERT INTO cache (daten) VALUES (':daten')");
        $insert->bindValue(':daten', "");
        $insert->execute();
    }
    else {
        $db=new PDO('sqlite:'.$datenbank);
    }

    $update=$db-> prepare("UPDATE cache SET daten = ':daten' WHERE id = 1");
    $update->bindValue(':daten', $daten);
    $update->execute();
}

...wobei ich mir immer noch keinen Reim auf ':daten' machen kann.
Also mit Vorsicht zu Geniessen.

Das Schliessen der Datenbank hab ich jetzt auch mal nicht eingebaut (ignoriert).
 
Zuletzt bearbeitet:
Es läuft jetzt wie es war. Schuld war die Rechteverwaltung von Linux. sas wurde daran gehindert, den Datensatz zu schreiben, aber irgendwie nicht ganz. Merkwürdiges Verhalten von sqlite. Nachdem volle Rechte von sasap gesetzt werden, läuft es.

Wie schließt man die Datenbank in dieser Syntax eigentlich?

Das :daten ist ein Platzhalter, der durch bindValue mit Daten belegt wird. Das ist schon ok. :)
 
Das Datenbankhandle holst du mit: $db=new PDO('sqlite:'.$datenbank);
Dann schliesst du es mit: $db=null;
...eigentlich zerstörst du die Variable $db damit, wenn ich mich nicht irre. ;)
Das kommt aber aufs Selbe raus und ist so dokumentiert.
 
Zuletzt bearbeitet:
Ah, danke dir, das war es, was mir noch fehlte. :)
 
Apropos Doku

Solche SQL Aufrufe für die PDO sqlite seh ich in den Beispielen meist eingekapselt im "Exception Handling" Konstrukt..
try{
throw{}
}
catch{}
...das muss was zu Bedeuten haben. :gruebel:
 
Die Alpha-Version läuft. :)
 
Und? Wie findest du es?
 
Geschwindigkeit passt. Ansonsten umständlicher. Für den Umstieg muss ich extra wieder eine Abfrage einbauen, wie die Abfrage wie nun die Struktur des Caches ist, weil wenn alt, dann crasht sas.

Trotzdem werde ich jetzt als nächstes das komplette Array mit Einzelwerten in die Datenbank bringen. Erst dann macht es wirklich Sinn, weil dann keine Schaltzustandsanzeige mehr verloren gehen kann. Das wird allerdings einiges an Arbeit werden. Vorher gebe ich die 3.00 nicht raus. Das kann jetzt etwas dauern.

Sollte das dann funktionieren, wäre ein vollkommen unabhängiges Schalten und Schreiben möglich, weil nur der eine Punkt, das eine Element verändert wird. sas wäre dann multi-interface-fähig. Auch andere Scipte könnten ihre Daten wie Sensorwerte unabhängig in die Datenbank schreiben. Mal sehen, was da sonst noch möglich wäre.
 
Yo, neuer Stoff.
Lass sacken. ;)
SQL ist aber ein robustes Werkzeug, wie PHP.
...duck und weg...
 
Der Plan: sasap - Pro (Pseudo)Gerät soll ein Datensatz in die Datenbank geschrieben werden. Entweder neu aufgenommen, wenn noch nicht existent oder update wenn vorhanden, direkt während der Geräteabfrage.
Gibt es eine Möglichkeit, dies ohne vorherige Abfrage zu händeln? Also update Datensatz, wenn nicht existiert lege ihn an?
Kann die ID der GeräteName sein?

sas - Schreibt den Datensatz des entsprechenden Gerätes bei einem Schaltvorgang. (update)
sasap - Schreibt ebenfalls den Datensatz des entsprechenden Gerätes bei einem Schaltvorgang. (update)

Nachtrag:
alles Scripte lesen ihren Datensatz zum jeweiligen Gerät bei Bedarf (sas bei der Anzeige usw.)
 
Zuletzt bearbeitet:
Nee

Das CREATE TABLE IF NOT EXISTS kenn ich so nur für Tabellen.

Solange die Datenbank offen ist machen die Abfragen aber nichts und sind fix.
PHP:
$sth = $dbh->prepare('SELECT id FROM cache WHERE id = 1'); // Ersten Datensatz mit id==1 holen
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
if ($Status=="") { // Wenn kein Datensatz vorhanden estellen
$count = $dbh->exec("INSERT INTO cache (daten) VALUES ('Ganz viel Text und so weiter und so fort"));
}
...ab jetzt macht auch erst ein Update Sinn.
Das prüft auf den Datensatz selber, aber id ist ja auch nur ein Feld.

Die Pseudogeräte und eins pro Datensatz, richtig?
idactivetypetempwattcommandcommand1command0
21S202.25https://snom2.fritz.box/command.htm?key=DNDhttps://snom2.fritz.box/command.htm?key=P11https://snom2/screen.bmp
11S202.25https://snom1.fritz.box/command.htm?key=DNDhttps://snom1.fritz.box/command.htm?key=P11https://snom1/screen.bmp
(Hier gibts noch keinen Namen, die id ist pro Skript "hardkodiert")
Da die id aber als "autoincrement" angelegt wird,
gibt es noch die Methode unabhängig von dieser
den Datensatz an einen anderen Feldnameninhalt zu Identifizieren.

Kurze Prüfung auf den (eindeutigen) Inhalt in den Datensätzen dann,
wenn nicht vorhanden anlegen, ansonsten updaten.

Die Pseudoskripte sind immer selber dafür verantwortlich, dass sie einen ordentlichen Datenbankeintrag bekommen.
...und müssen deshalb auch die dafür notwendigen Prüfungen erledigen.
Bei der obigen Tabelle könnten die Skripte sich an den "commands" erkennen.
...denn sie haben es selber in die Datenbank schreiben lassen. ;)

Beispiel eines der oben in der Liste angezeigten Pseudoskriptes...
pseudosnom1.php (läuft so schon seit Monaten bei mir)
PHP:
<?php // Schalter speichert/liest/liefert Schaltzustand aus SQLite3 Datenbank, Tabelle: pseudodevice
require_once("db.php");// SQLite3 Datenbankoeffner
require_once("include/includefunctions.php");
$p_id=1;// Diese id aus der Datenbank gehoert diesen Schalter
try {// Dann versuchen wir es mal...
$count = $dbh->exec("CREATE TABLE IF NOT EXISTS pseudodevice (id INTEGER PRIMARY KEY, active VARCHAR(255), type VARCHAR(255), temp VARCHAR(255), watt VARCHAR(255), command VARCHAR(255), command0 VARCHAR(255), command1 VARCHAR(255))");
$sth = $dbh->prepare('SELECT id FROM pseudodevice WHERE id = '.$p_id.'');
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
if ($Status=="") {
$count = $dbh->exec("INSERT INTO pseudodevice (active,type,temp,watt,command,command0,command1) VALUES ('1','S','20','2.25','https://snom1.fritz.box/command.htm?key=DND','https://snom1/screen.bmp','https://snom1.fritz.box/command.htm?key=P11')");
}
if ($_GET[info]=="status") {
$sth = $dbh->prepare('SELECT active,type FROM pseudodevice WHERE id = '.$p_id.'');
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
if ($Status[active]=="1") {
throw new Exception(trim($Status[type])."#".trim($Status[active])."#");
}
if ($Status[active]=="0") {
throw new Exception(trim($Status[type])."#".trim($Status[active])."#");
}}
if ($_GET[schalter]=="1") {
$count = $dbh->exec("UPDATE pseudodevice SET active = '1' WHERE id = ".$p_id."");
$sth = $dbh->prepare('SELECT id,active,type,command FROM pseudodevice WHERE id = '.$p_id.'');
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
if ($Status[active]=="1") {
web($Status[command],"");
throw new Exception(trim($Status[type]."#".$Status[active])."#");
}}
if ($_GET[schalter]=="0") {
$count = $dbh->exec("UPDATE pseudodevice SET active = '0' WHERE id = ".$p_id."");
$sth = $dbh->prepare('SELECT active,type,command FROM pseudodevice WHERE id = '.$p_id.'');
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
if ($Status[active]=="0") {
web($Status[command],"");
throw new Exception(trim($Status[type]."#".$Status[active])."#");
}}
throw new Exception($Status[type]."##E##");
}
catch(Exception $e) {
echo $e->getMessage();
}
?>
Wenn selbst die Datenbank nicht vorhanden, erstellen, wenn kein Eintrag zum Pseudo, erstellen, dann normaler Ablauf.
Hier noch mit der hardkodierten id: $p_id=1;// Diese id aus der Datenbank gehoert diesen Schalter
Jede SaS Statusmeldung wird im try{} mit throw() vorbereitet und im catch{} für SaS bereitgestellt.
 
Zuletzt bearbeitet:
So ähnlich, aber die PseudoScripte dürfen nichts mit der sas-Cache-Datenbank zu tun bekommen. Du vergisst die Fritzbox gemeldeten Geräte wie DECT200, die nicht auf PseudoScripten beruhen. Außerdem wollen die Benutzer sicher nicht für ihre PseudoScripte alles neu machen. Das bleibt alles wie es ist. sasap wird die allgemeine Datenbankflege übernehmen und sas wird vom Benutzer ausgehende Schaltvorgänge gezielt für den jeweiligen Schaltvorgang dort einpflegen.

Außerdem genügen drei Felder pro Datensatz/Gerät: ID, Name (bzw. eigentliche Identifikation) und ein Feld für das Array mit dem Rest. Alles andere wäre unnötiger, änderungsintensiver Aufwand.

Da ich früher nur in Informix und den PseudoAccess-Datenbankkram von MS programmiert habe, kämpfe ich etwas mit der SQLite-Syntax. Ich weiß nur immer, dass etwas funktionieren muss, aber nicht wie genau die "neue" Syntax dazu aussieht. Daher werde ich erst ein wenig mit einer Versuchsdatenbank experimentieren. Glücklicherweise braucht man bei PHP nicht wie früher einen Datenbankserver, sondern es funktioniert on the fly. ;)
 

Statistik des Forums

Themen
246,198
Beiträge
2,247,888
Mitglieder
373,756
Neuestes Mitglied
MarieDobbs
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.