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

JL3

Aktives Mitglied
Mitglied seit
4 Dez 2010
Beiträge
1,995
Punkte für Reaktionen
8
Punkte
38
Das Szenario: SAS-WebGUI ist an verschiedenen Geräten aufgerufen. Wird nun an mehr als einem etwas geschaltet, so kommt es vor, dass sich die SAS-WebGUIs beim Schreiben der Veränderung in den Cache so sehr in die Quere kommen, dass der Cache-Inhalt zerstört wird. Zwar wird dieser durch sasap nach ca. einer Minute wieder aufgebaut, aber in dieser Zeit herrscht etwas Chaos, was dazu führen kann, dass sogar falsche Geräte geschaltet werden.

Das Szenario ist selten aber rekonstruierbar.

Daraus ergibt sich eine Frage zu PHP, zu der ich keine verlässliche Antwort im Internet gefunden habe. Ich könnte, wenn eine SAS-WebGUI schaltet, per erzeugter "Busy"-Datei anderen signalisieren, dass sie warten müssen, doch, was ist, wenn der Benutzer während das Script abläuft, den Browser schließt oder das Gerät ausschaltet, bevor die WebGUI die "Busy"-Datei wieder entfernen kann? Wie lange läuft das PHP-Script? Wird es durch das Beenden der Verbindung einfach unterbrochen? Dann wäre eine "Busy"-Datei zum Anzeigen der Beschäftigung nicht sinnvoll, weil man nie vorhersagen kann, was der Benutzer gerade macht. Doch welche Alternative gäbe es?

Wer könnte mir dazu Infos geben oder hätte eine Idee?
 
Zuletzt bearbeitet:
Moin

Verstehe, vielleicht etwas rigeros aber zielführend...
Einen Betrachterzähler einbauen und anhand von diesen die Benutzung,
beziehungsweise das Schalten abhängig machen.
...wäre ein Workaround.
 
Nur wie stelle ich fest, ob der Betrachter gerade etwas schalten will? Und wie meldet er sich ab, wenn er einfach den Browser schließt?

Wie verhält sich PHP, wenn der Browser während das Script läuft, geschlossen wird? Ich denke, das wäre zunächst die elementarste Frage. Läuft es zu Ende, bricht es ab. Meldet es ein Fehlerflag?

Zumindest den Abbruch kann man wohl verhindern: ignore_user_abort(true);
 
Zuletzt bearbeitet:
Ich denke, hier rächt sich das rechtelose Konzept von SaS.
Wäre die Steuerung von SaS nur über Benutzer/Passwort möglich,
würde ich das eher gelassen sehen.

So kann ja jeder Googlebot, wenn er denn den Weg zu SaS findet,
auch als Betrachter gezählt.

Ein eingeloggter Benutzer zählt als potenzieller "Schalter" bis er ausgeloggt ist.

Inwieweit eine PHP Sessionid hier helfen könnte?
Eigentlich dient die nur dazu, ein Timelimit für nicht mehr agierende Klienten zu definieren.
 
Zuletzt bearbeitet:
Lässt du Google echt auf dein Heimnetzwerk Zugriff nehmen????????? :mrgreen:

Sorry, aber das trifft weder das Kernproblem noch wäre diese übertriebene Wahn sonstwie hilfreich, da man erst mühsam z. B. am Tablet sich kompliziert anmelden müsste, nur um schnell etwas zu schalten. Es verhindert auch nicht, dass gerade zwei angemeldete Benutzer schalten.

Gleiches Problem mit SessionIDs. Auch hier nicht zielführend. Die Problematik ist, das Verhindern des gleichzeitigen Schreibens von Veränderungen in den Cache. Also eine zeitlich sehr kurzfristige Sperre für währed des Schreibvogangs. Alles Aufgeführte kann dies nicht verhindern. Ich will ja nicht die ganze Zeit, wenn ein User angemeldet ist, alle anderen am Schalten hindern. Wäre unsinnig, oder?

Und noch was zu dem "Sicherheitswahn". Wer es ins Heimnetzwerk schafft, kommt auch weiter, egal, was da angestellt wird. Es erschwert nur dem Nutzer das Benutzen. :mrgreen:
 
Zuletzt bearbeitet:
Nee, aber ich weiss wie schnell der Googlebot auf eine Freigabe fürs Internet reagiert (HTTP/HTTPS Standardports). ;)

...und zwar, weil ich darüber eine Zugriffsdatenbank (SQLite3) geführt habe.

Und ich weiss auch, dass er auf die robots.txt achtet/hört.
robots.txt
Code:
# robots.txt for this site
User-agent: *
Disallow: /

Abgesehen davon, gibt es jede Menge an Fritz!Boxlern die gefunden werden wollen.

Suchbegriff: site:.myfritz.net
 
Zuletzt bearbeitet:
Würde ich nicht freigeben. Wer Einladungen verschickt, darf sich über Besuch nicht wundern. ;)

Aber Spaß beiseite, es hilft nichts bei der beschriebenen Problematik.
 
Zuletzt bearbeitet:
Auch keine Rechteverwaltung in der minimalsten Form von einem Account zum Schalten?
 
Da reden wir wohl aneinander vorbei. Eine Rechteverwaltung bringt da überhaupt nichts, wenn zwei User gleichzeitig schalten.
 
Nun, es muss erstmal darum gehen, wie SaS überhaupt merkt, dass zwei Benutzer schalten könnten.
...oder 5, 9, 80 ?

Ganz doof gesagt:
SaS: Ereignis: Uhrzeit - Benutzer hat Webinterface aufgerufen
SaS: Ereignis: Uhrzeit - Benutzer hat Schalter sowieso betätigt
...
...im Webinterface für jeden Klient sichtbar.
Und das am Besten in "Echtzeit" als "Chatmeldung".
Eine Chatzeile wäre dann auch nicht verkehrt. ;)

Restriktiver, ohne grossartige Prüfung ob und wieviel Benutzer schalten könnten, wäre...
Der crond sasap.php erlaubt nur 1 Webinterface (Wer zuerst kommt malt zuerst) zum Schalten und Einstellen u.s.w.
Jeder weitere Aufruf eines Webinterfaces ist nur: Zum Zuschauen (gesperrt)
 
Zuletzt bearbeitet:
Nein, immer noch der falsche Denkansatz bei dir. Ob ein oder zwei oder mehr "angemeldet" sind, ist uninteressant. Ob zwei gleichzeitig schalten, darauf kommt es an und wie man das händelt. sasap prüft übrigens nichts. sas schaltet selbst und macht ein Update des Cache (worin das Problem liegt). Der Kern des Problems ist die Kollision beim Schreibzugriff auf den Cache.

Aber ich habe inzwischen eine Möglichkeit erarbeitet. Eine Möglichkeit: WebGUIs und sasap schalten überhaupt nicht mehr, sondern starten per Betriebssystem-Befehl ein reines Schalttool, welches prüft, ob weitere Schalttools gerade laufen. Da deren Laufzeit höchstens eine Sekunde beträgt (eher weniger), warten die jeweiligen Tools auf die Beendigung des vorangegangenen. So werden alle Schaltvorgänge abgearbeitet und immer nur eines schreibt in den Cache. Ich bastle aber an einer noch eleganteren Möglichkeit. Muss ich aber erst testen. Kommt dann wohl mit der V 3.00.

Dein Vorschlag hingegen würde immer alle bis auf einen ewig lahmlegen, was nicht Sinn und Zweck des Ganzen sein sollte, denke ich mal. ;)
 
Was passiert denn bei gleichzeitigen Schalten? Der Letzte der reinkommt, gewinnt, oder? Es wird nur 1x geschaltet/min? Kein temporäres Array von gleichzeitigen Aktionen? ...eigentlich muss doch nur aufgepasst werden, dass beim crond Aufruf nichts schief läuft. Dann können 10 User ja wieder "Schiffe versenken" spielen.
 
Das Problem ist folgendes. Das Schalten an sich ist sogar noch egal.

Nehmen wir mal ein Beispiel:

Benutzer1 schaltet Dose1 an
Benutzer2 schaltet gleichzeitig Dose2 an

Die Schaltvorgänge werden problemlos ausgeführt, aber...
sas von Benutzer1 schreibt nun den Cache mit veränderten Statusangaben neu.
sas von Benutzer2 schrebt aber nun gleichzeitig ebenfalls den Cache neu und die Cachedatei ist zerstört, bis irgendwann sasap aus den Realdaten einen neuen Cache erstellt.

Mit mehr als einem Script gleichzeitig in eine Datei zu schreiben macht fast immer Probleme. Das abzufangen ist die Schwierigkeit und im PHP-Handbuch kennt man ebenfalls das Problem und keine 100%ige Lösüng dazu.

Nachtrag: Dass die Anzeige eine Minute hinterherhinkt wäre ein Rückschritt und auch unpraktisch. Schaltet man ein, muss man eine Minute warten, bis man ausschalten könnte.
 
Zuletzt bearbeitet:
Ergo: Das sequentielle Schreiben sollte in solchen Fällen nichts durcheinanderbringen. Damit mein ich nicht den gesamten Cache, sondern nur in ihm betroffene Variablen zu ändern. Bei einer reinen Datei könnte das trotzdem noch problematisch sein. Dazu fällt mir eigentlich als erstes wieder mal SQLite3 ein. Soweit ich das bis jetzt mitgekriegt habe kümmert sich die Datenbank selber um solche Sachen. ...und sequentielles Lesen/Schreiben ist dabei eine Kleinigkeit.
 
Ja, das würde das Problem beheben. Eine Datenbank regelt ihre Zugriffe selbst.

Doch gibt es für die Fritzbox mips/mipsel entsprechendes? Wenn ja, ist der Zugriff schnell genug? Und ist die Einrichtung für einen normalen User machbar?
Beim Pi kann man sicher entsprechendes nachinstallieren.

Wie ich sehe, kommt es da sehr auf die php-Version an, ob SQLight2 oder 3 möglich ist. Wie das unter einen Hut bekommen?

Nachtrag: Ich werde das bei Gelegenheit mal testen. Wichtig wäre nur, dass es ohne viel Aufstand für den Benutzer abläuft, sowohl Pi als auch FB.
 
Zuletzt bearbeitet:
PDO (sqlite) Erweiterung nennt sich das wohl in PHP.
Einfache Beispiele dafür liegen SaS ja schon bei. ;)
SQLite3 ist deswegen auch so händisch, weil die Datenbank mit Zugriff on the fly erstellt werden kann.
...wenn sie nicht existiert.
 
Zuletzt bearbeitet:
Bevor ich jetzt lange rumexperimentiere...

vielleicht kannst du mir schnell weiterhelfen:

Datenbank tmp/sas.data erstellen, wenn nicht existiert
dann möchte ich einen Datensatz in eine Tabelle schreiben, der aus einem String besteht und eine variable Länge hat. Länge ist bis etwa 64kb
Datenbank schließen

Und andersrum
Datenbank tmp/sas.data erstellen, wenn nicht existiert
dann möchte ich einen Datensatz aus eine Tabelle lesen, der aus einem String besteht und eine variable Länge hat. Länge ist bis etwa 64kb
Datenbank schließen

Geht das, oder gibt es da Probleme mit der String-Länge?

Kannst du da bitte mal ein Beispiel posten?

Nachtrag: Hat sich erledigt, hab schon was gebastelt. :)
 
Zuletzt bearbeitet:
Datenbanköffner
db.php
PHP:
<?php
date_default_timezone_set('Europe/Berlin');
$strDatenbank = 'sqlite:/tmp/sas.data';
$dbh = new PDO($strDatenbank);
?>

Das PHP Skript
PHP:
require_once("db.php");// SQLite3 Datenbankoeffner
$count = $dbh->exec("CREATE TABLE IF NOT EXISTS tabelle (id INTEGER PRIMARY KEY, cache VARCHAR(65335))"); // Erstellen falls nicht existent
$sth = $dbh->prepare('SELECT id FROM tabelle 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 tabelle (cache) VALUES ('Ganz viel Text und so weiter und so fort"));
}
$sth = $dbh->prepare('SELECT id FROM tabelle WHERE id = 1'); // Ersten Datensatz mit id==1 holen
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
// Jetzt steht obiges in $Status['cache'] == 'Ganz viel Text und so weiter und so fort"

So wird ein update auf einen Datensatz gemacht.
PHP:
$count = $dbh->exec("UPDATE tabelle SET cache = 'wieder viel text' WHERE id = 1");
$sth = $dbh->prepare('SELECT cache FROM tabelle WHERE id = 1');
$sth->execute();
$Status = $sth->fetch(PDO::FETCH_ASSOC);
// Update steht jetzt in der Tabelle und $Status['cache']
 
Zuletzt bearbeitet:
Meine Lösung sieht irgendwie komplizierter aus: :gruebel:

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`");
	$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");
	$update->bindValue(':daten', $daten);
	$update->execute();
}

Kanns du mal einen Blick drauf werfen?
 
Zuletzt bearbeitet:
Moin

Ganz langsam.

1. Den Cache komplett in eine Tabelle als riesigen String zu quetschen ist nicht sequentiell.
2. Denn auch hier muss ja immer der komplette Cache "ausgetauscht" werden.
3. Deswegen muss die Tabelle mit ihren einzelnen Feldern genau wie der Cache aufgebaut werden.
4. Einzelne Datensätze in der Tabelle haben dann genau diese Struktur.
5. Dann erst kann gezielt (sequentiell) ein Update auf ein einzelnes Feld im Datensatz erfolgen.

Deswegen ist die Konzeption am Anfang am Wichtigsten und sollte erst mal ständig überprüft werden.
Dazu bau ich mir gern ein Datenbankanzeige.php die natürlich mit jeden neuen Feld auch angepasst werden muss.

Für jede SQLite3 Datenbank gilt übrigens...
master.php
PHP:
<?php
include("db.php");
try {
  $dbh = new PDO($strDatenbank);
  $sth = $dbh->prepare('select rowid, * from sqlite_master');
  $sth->execute();
  sleep(0.125);
  $dbh = null;
$dbh = null;
echo '<table border="1"
style="background:fixed 0% 0% repeat olive url(/rte/img/bg.jpg);
table-layout:fixed;
border:3px double olive;
border-collapse:inherit;
border-spacing:3px 5px;">
<tr><th>type</th><th>name</th><th>tbl_name</th><th>rootpage</th><th>sql</th></tr>';
while($Zeile = $sth->fetch(PDO::FETCH_ASSOC)){?>
<tr>
<td><?php echo $Zeile['type']; ?></td>
<td><?php echo $Zeile['name']; ?></td>
<td><?php echo $Zeile['tbl_name']; ?></td>
<td><?php echo $Zeile['rootpage']; ?></td>
<td><?php echo $Zeile['sql']; ?></td>
</tr>
<?php
}
echo '</table>';
}
catch(PDOException $e) {
  echo $e->getMessage();
}
?>
Eine Mastertabelle muss in jeder SQLite3 Tabelle enthalten sein (wird automatisch angelegt)
und enthält die Informationen wie Tabellen in der Datenbank angelegt wurden (also die Struktur).
 
Zuletzt bearbeitet:
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.