Einführung:
Manch einer möchte mit seinem RaspberryPI etwas in Datenbanken schreiben aber nutzt hierfür das allgemein verbreitete MySQL, das aber eigentlich erst auf vernünftigen Servern zum Einsatz kommt - also solche die sowohl genug CPU als auch RAM haben...
MySQL hat nämlich den Nachteil das eine Server-Software benötigt wird: der MySQL Daemon
Der verbraucht aber permanent relativ viel RAM, auch wenn die Datenbanken garnicht genutzt werden...
Da der RPI aber nicht wirklich sooo viel RAM und CPU Leistung hat, reicht es für kleinere Projekte wie Temperatur Messungen oder allgemein Sensoren usw auch eine Resourcen-schonendere Datenbank-Software zu nutzen: SQLite
SQLite Installation:
Zunächst möchte ich euch beschreiben wie ihr SQLite für sowohl die Konsole als auch den Webserver installiert:
Für die Konsole - um SQLite zB auch in bash Scripts benutzen zu können, benötigt ihr folgendes:
Für den Webserver (apache2 oder lighttpd) benötigt ihr:
Entsprechende PHP5 Module natürlich vorrausgesetzt:
für apache2: apt-get install php5
für nginx: apt-get install php5-fpm
für lighttpd: apt-get install php5-cgi
Web-based Admin Tool:
Für MySQL gibt es ja ein sehr bekanntes Admin Tool für den Browser: phpMyAdmin
Das gibts natürlich auch für SQLite:
http://code.google.com/p/phpliteadmin/
Der grösste Vorteil hierbei ist das nur eine einzige php Datei benötigt wird: phpliteadmin.php
Ein Nachteil wäre u.U. das man nur ein Passwort festlegen kann, man kann also nicht mehrere Benutzer festlegen die auf unterschiedliche Datenbanken Zugriff haben, aber ich denke das kann man im Bezug auf den Raspberry auch ausser Acht lassen
Falls gewünscht kann ich auch noch auf die Installation und Einrichtung näher eingehen aber das lass ich hier jetzt erstmal weg, sollte eigentlich selbsterklärend sein
Eine Alternative dazu wäre aber auch: http://sourceforge.net/projects/sqlitebrowser/
Anwendung:
Nun ans Eingemachte
Im Gegensatz zu MySQL werden bei SQLite einzelne Datenbank-Dateien verwendet. Wenn man SQLite ausschlieslich über die Konsole, also mit bash / sh oder python Scrpts benutzen möchte sähe das folgendermassen aus:
Anwendung über die Konsole:
Beim sqlite3 Befehl muss das erste Parameter die Datenbankdatei sein und danach kommt der jeweilige Befehl in Gänsefüsschen-oben ( " ).
Anhand eines Beispiels lässt sich das denk ich am besten erklären:
sqlite3 /var/www/db.sqlite "CREATE TABLE IF NOT EXISTS settings (id INTEGER PRIMARY KEY,user_id INT,setting TEXT,value TEXT);"
/var/www/db.sqlite ist die Datenbankdatei
CREATE TABLE IF NOT EXISTS sorgt dafür das eine Tabelle nur dann erzeugt wird falls diese noch nicht existiert
settings ist der Name der Tabelle
(id INTEGER PRIMARY KEY,user_id INT,setting TEXT,value TEXT) sind die Spalten mit den dazugehörigen Typen die in der Tabelle settings erzeugt werden sollen (INT ist eine Abkürzung für INTEGER)
Der Name der Datenbankdatei ist übriegends egal, könnt ihr frei wählen
Eine genauere Beschreibung der möglichen SQLite Syntax könnt ihr hier nachlesen: http://www.sqlite.org/lang.html
Welche Typen möglich sind könnt ihr unter "CREATE TABLE" nachlesen
Ausserdem gibt es auch einen Weg zu prüfen ob in der Datenbankdatei eine entsprechende Tabelle überhaupt existiert:
sqlite3 /var/www/db.sqlite "SELECT count(name) FROM sqlite_master WHERE type='table' AND name=\"settings\""
Eine Tabelle sqlite_master muss hierfür nicht extra erzeugt werden, das ist eine SQLite interne Tabelle...
Der Ausgabewert wäre entweder 1 wenn die Tabelle settings existiert oder 0 wenn nicht. Das könnte man also auch in ein Script paken was erst prüft ob eine Tabelle existiert und falls nicht wird sie angelegt, aber dazu gerne später mehr falls gewünscht
Eine Datenbank-Abfrage könnte so aussehen:
Das verarbeiten einer solchen Datenbank-Abfrage gestaltet sich in bash/sh allerdings leider etwas umständlich:
dbLIST=( $(sqlite3 /var/www/db.sqlite "SELECT * FROM auth WHERE 1") )
oldIFS=$IFS ; IFS=$'\n'
for ROW in "${dbLIST[@]}"; do
# Parsing data (sqlite returns a pipe separated string)
ID=$(echo $ROW | awk '{split($0,a,"|"); print a[1]}')
USER=$(echo $ROW | awk '{split($0,a,"|"); print a[2]}')
PASS=$(echo $ROW | awk '{split($0,a,"|"); print a[3]}')
# Printing my data
echo "$ID) "$USER" -> "$PASS;
done
IFS=$oldIFS
Alles anzeigen
Anwendung über PHP:
In PHP gäbe es 2 verschiedene Wege - wenn ihr über google nach "php sqlite" sucht dann findet ihr leider die veralteten "sqlite_open()" usw Befehle zB auf php.net, aber das ist primär für die etwas ältere SQLite2.. Teilweise lässt sich das auch mit SQLite3 verwenden aber irgendwann stösst man an die Grenzen des Machbaren und dann wäre es ziemlich ärgerlich alle bereits geschriebenen PHP Scripte umschreiben zu müssen - deshalb lieber von Anfang an mit PDO arbeiten
PDO bietet für viele verschiedene SQL Datenbank-Typen einheitliche und übergreifende Befehle, man kann also die selben Befehle für sowohl SQLite als auch MySQL oder MSSQL usw nutzen - und ist zudem auch schnell(er)
Ich gehe an dieser Stelle kurz auf einen wichtigen Punkt ein der nachfolgend klarer werden sollte:
Wenn ihr in euren Scripts (php oder bash ist egal) öfters immer wieder die selben Dinge ausführen wollt, also der Code sich im Prinzip wiederholt, dann nutzt am besten sogenannte " function " s
Das hat den einfachen Grund das ihr nur den Code in dieser function verändert brauch aber nicht 20x im ganzen Script verstreut
Function's sind im grunde sowas wie Befehle die ihr deklariert und später an x-beliebiger Stelle immer wieder ausführen könnt
Ich habe in meinen PHP Scripts folgende Functions in Benutzung mit denen ich sowohl das Ansprechen der Datenbankdatei regel als auch die Datenbankabfragen - und fehler die ggf beim öffnen der Datenbankdatei auftreten usw
[code=php]// DB connect
function db_con($DBfile) {
if (!$db = new PDO("sqlite:$DBfile")) {
$e="font-size:23px; text-align:left; color:firebrick; font-weight:bold;";
echo "<b style='".$e."'>Fehler beim öffnen der Datenbank $DBfile:</b><br/>";
echo "<b style='".$e."'>".$db->errorInfo()."</b><br/>";
die;
}
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $db;
}
// DB Query
function db_query($sql) {
global $db;
$result = $db->query($sql) OR db_error($sql,$db->errorInfo());
return $result;
}
// DB errors
function db_error($sql,$error) {
die('<small><font color="#ff0000"><b>[DB ERROR]</b></font></small><br/><br/><font color="#800000"><b>'.$error.'</b><br/><br/>'.$sql.'</font>');
}
// Add HTML character incoding to strings
function db_output($string) {
return htmlspecialchars($string);
}
// Add slashes to incoming data
function db_input($string) {
if (function_exists('mysql_real_escape_string')) {
return mysql_real_escape_string($string);
}
return addslashes($string);
}[/php]
Die functions könnt ihr im PHP Script an jede x-beliebige Stelle einfügen - manche setzen sie nach ganz unten, andere wiederum erstellen dafür eine extra Datei die im Hauptscript dann included wird...
In dem eigentlichen PHP Script würde dann folgendes stehen:
[code=php]$SQLITEdb = "/var/www/db.sqlite";
$db = db_con($SQLITEdb);
$query = $db->query("SELECT pass FROM auth WHERE user='".$USER."'");
$result = $query->fetch(PDO::FETCH_ASSOC);
if ($result['pass'] == md5($PWD)) {
$query = $db->query("UPDATE auth SET lastlogin='".time()."' WHERE user='".$USER."'");
}[/php]
$SQLITEdb legt die Datenbankdatei fest - ihr könnt aber natürlich auch mehrere nutzen..
$db = db_con($SQLITEdb); damit wird die function db_con mit dem Parameter der Datenbankdatei aufgerufen - wenn ihr unterschiedliche Datenbankdateien nutzen wollt könnt ihr an dieser Stelle auch $db = db_con("/var/www/db2.sqlite"); nutzen
$query = $db->query("SELECT pass FROM auth WHERE user='".$USER."'"); nutzt in diesem Fall keine meiner functions sondern eine php übliche pipe ( -> ). $USER ist eine Variable die ich vorher über $_POST erhalten und abgefragt habe.. der Rest sollte hoffentlich klar sein
$result = $query->fetch(PDO::FETCH_ASSOC); hier wird nun ein PDO globaler Befehl genutzt um die Rückgabewerte des query's in das Array $result zu schreiben, die dann anschliesen genutzt werden können:
if ($result['pass'] == md5($PWD)) { hier wird nun der Rückgabewert des query's verwendet, in diesem Fall aus der Spalte "pass" des Benutzers $USER
Eine weitere Möglichkeit mit Rückgabewerten umzugehen wäre auch folgendes:
[code=php]$db = db_con($SQLITEdb);
$query = $db->query("SELECT id,user FROM auth WHERE 1");
while($result = $query->fetch(PDO::FETCH_ASSOC)){
$id = $result['id'];
$AddedUsers[$id] = $result['user'];
}
[/php]
Hier wird eine while Schleife genutzt weil mehr als eine Zeile zurückgegeben werden könnte. Es befinden sich also mehrere verschiedene Einträge in der Tabelle " auth "
Und auch noch mal ein Beispiel zu meiner db_query function:
[code=php]$db = db_con($SQLITEdb);
$query = $db_query("SELECT pass FROM auth WHERE user='".$USER."'");[/php]
Das wars dann eigentlich schon - ich hoffe das war nicht allzuschwer beschrieben :s , ansonsten beantworte ich euch gerne weitere Fragen
//EDIT:
Bezüglich Python siehe folgende Beiträge:
SQLite Auslesen und mit Wert vergleichen
Highscore-Liste
Daten aus Dateien einlesen und als Variablen verwenden
//EDIT: Wichtiger Hinweis bezüglich Python: Wie sage ich es in Python ? (Einsteigerfragen)