Anfänger mit Drupal benötigt Hilfe bei einer SQL-Abfrage
Eingetragen von atomicx (5)
am 28.04.2008 - 00:08 Uhr in
am 28.04.2008 - 00:08 Uhr in
Grüsse Euch
Mein Problem:
Unten im Footer möchte ich eine kleine Statistik über die Besucher meiner Seite machen und zwar mittels Block. Den PHP-Filter habe ich installiert. Nun ich schaffe das einfach nicht eine SQL-Abfrage zu machen in diesem Block. Es passiert einfach nichts! Die Datenbank und die Tabellen existieren, sonst sollte es auch funktionieren, habe es ohne Drupal getestet.
Hier der wichtige Teil:
.............VER['HTTP_REFERER'];
$sql='SELECT `ip` , `unixtime` FROM `counter` WHERE `ip` LIKE \'' . $ip . '\'';
$erg=db_query($sql);
while($a=mysql_fetch_object($erg)){
$ip=$a->ip;
$unixtime1=$a->unixtime;
}
// Sicherheitssperre 2 Minuten für die selbe IP
$time=$unixtime-$unixtime1;
if($time>120){
$sql1='INSERT INTO `counter`.`counter` (`id`, `ip`, `datum`, `unixtime`, `dns`, `browser`, `referer`) VALUES (NULL, \''. $ip . '\', \'' . $datum . '\', \'' . $unixtime . '\', \'' . $dns . '\', \'' . $browser . '\', \'' . $referer . '\');';
$erg=db_query($sql1);
}........................
Wer noch etwas weiterlesen möchte:
Könntet ihr mir auch noch ein paar Linktipps geben, wo ich Beispiele sehe, bin euch sehr dankbar :)
Freundliche Grüsse aus der Schweiz.
- Anmelden oder Registrieren um Kommentare zu schreiben
Arbeiten mit der Datenbank
am 28.04.2008 - 06:55 Uhr
schau mal ob dir das weiter hilft, ich hatte das mal für mich aufgeschrieben. Ich benutze hier eine eigene Funktion, denke aber das das für das Grundverständnis ausreichend ist ohne die vollständige Anwendung zu kennen. Versuche erst einmal die Ergebnisse auszulesen, entweder mit dem DEVEL-Modul oder mit einem einfachen drupal_set_message(). Kümmer dich dann darum wie du die Ergebnisse in den richtigen Block bekommst
Drupal ist in der Lage mit verschiedenen Datenbanken zu arbeiten. Die Auswahl wird in der Regel bei der Installation getroffen. Ferner ist Drupal in der Lage auch weitere Datenbanken (exterene Datenbanken) einzubinden.
Die Einbindung der Datenbank ist im Script
./sites/default/settings.php
niedergelegt.$db_url = 'mysql://username:password@localhost/databasename';
oder
$db_url = 'mysqli://username:password@localhost/databasename';
oder
$db_url = 'pgsql://username:password@localhost/databasename';
$db_prefix = '';
Mit dem Prefix
$db_prefix = '';
kann ein Datenbank-Prefix, z. B. drupal_tablename, festgelegt werden. Diese Option ist immer dann zu empfehlen, wenn man nicht nur mit Standard-Modulen arbeiten möchte oder mehrere Distributionen in einer Datenbank laufen lassen möchte. Hierbei ist einzig zu beachten das die Table in den Querys entsprechend gekennzeichnet sind SELECT * FROM {table_name};. Durch den Einsatz der geschweiften Klammer kann Drupal die entsprechenden Table-Prefixe ersetzen und parst die Query zuSELECT * FROM prefix_table_name
(Funktion db_prefix_tables($spl) in Script ./includes/database.inc). Sobald Module mit ander User geteilt werden soll muss man darauf achten, man weiß ja nicht wie der andere User die Datenbank anlegt.Drupal stellt dann ein Reihe von Funktionen zur Verfügung mit denen die Datenbankoperationen ausgeführt werden können. Leider stehen nicht alle Funktionen aus dem PHP-Manual MySQL-Funktionen zur Verfügung. Diese können aber auch direkt aufgerufen werden, hier sollte man die Sicherheit der Abfragen beachten.
Hier die wichtigsten Funktionen für MySQL (aus dem Script ./includes/datase.mysql.inc):
db_query($query)
Die Grundfunktion der Query. Hier nutzt Drupal die "Prepared Statements"-Syntax, bei der die Query "nackt", d. h. ohne Daten, übergeben wird und die Daten erst nach Prüfung eingefügt werden (siehe Erklärung nächste Seite).
db_affected_rows()
Gibt die Anzahl der betroffenen Zeilen einer Query zurück (für UPDATE, INSERT und DELETE).
db_error()
Gibt die Fehlermeldung einer Anfrage zurück. Leider fehlt hier die Funktion mysql_errno().
db_escape_string($text)
Setzt vor bestimmten Zeichen ein "/".
db_fetch_array($result)
Liefert ein Array mit dem Ergebnis einer Zeile der Abfrage; nur für SELECT-Anweisungen.
db_fetch_objekt($result)
Liefert ein Objekt mit dem Ergebnis. db_fetch_object() ähnelt db_fetch_array(), mit einem Unterschied - ein Objekt wird zurück geliefert anstatt eines Arrays. Indirekt bedeutet dies, dass Sie die Daten nur mit ihren Feldnamen und nicht mit dem Offset ansprechen können (Nummern sind ungültige Namen für Eigenschaften).
db_next_id($name)
Da Drupal keine auto_increment in den Datenbanken verwendet, wird über die Funktion db_next_id($name) der nächste frei Key geholt. Normalerweise ist das der größte Key + 1. Drupal kann etwas durcheinanderkommen, wenn Schlüssel manuel in der Datenbank gelöscht werrden - also Vorsicht. Die Syntax ist einfach $name = {table_name}_gewünschteID, also z. B. die nächste freie UID $naechsterUser = db_next_id('{users}_uid');.
db_num_rows($result)
Anzahl der Treffer eines SELECTS.
db_table_exists($table)
Abfrage ob eine bestimmte Tabelle vorhanden ist.
Für MySQLI und PostgreSQL stehen ähnliche Scripte mit gleichen Funktionen unter ./includes/datase.mysqli.inc und ./includes/datase.pgsql.inc bereit.
Datenbankabfragen als Prepared Statements
Die Syntax ist eigentlich simpel; es wird eine normale Query formuliert und die Werte werden nur mit Platzhaltern versehen. Diese Platzhalter werden dann nach Prüfung durch die eigentliche Werte ersetzt.
$user->uid = 12;
$result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
Erstellt wird daraus die Query
'SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = 12'
. Werden mehrere Platzhalter verwendet, müssen diese in der richtigen Reihenfolge angegeben werden. Gleiche Werte sind dabei auch mehrfach nazugeben.Sieht einfach aus - aber warum der Aufwand? Ganz einfach: So können SQL-Injections verhindert werden und vorbereitete Statements können schneller reprudziert werden (werden schneller ausgeführt).
Wichtig ist dabei die korrekte Syntax der Daten anzugeben, d. h. wie sollen sie Daten geprüft werden. Es gibt fünf Datentypen die entsprechend geprüft werden können:
%s
Prüft ob es sich um einen STRING handelt.
%d
Prüft ob es sich um einen ITERGER handelt.
%f
Prüft ob es sich um einen FLOAT handelt.
%b
Prüft ob es sich um einen BINARAY DATA handelt. Diese dürfen nicht in '' gekapselt werden.
%%
Prüft ob es sich um einen LITERAL handelt.
Insbesondere bei Strings sollte man allerdings sehr vorsichtig sein und ggf. noch mal eine gesonderte Prüfung einbauen bevor man die Daten mit der Query weitergibt. Als kleines Beispiel für eine schlechte Passwort-Abfrage:
$user = 'wackelpudding' OR uid = 1; --';
$pass = 'abc';
SELECT uid FROM users WHERE name = '.$username.' AND pass = MD5('.$password.')
// daraus wird:
// SELECT uid FROM users WHERE name = "wackelpudding" or uid = 1
// Das Ergebnis ist immer die UID des 1 Drupal-User (Administator)
Um solche Injections abzuwähren reicht ein einfaches Ersetzen bestimmter Strings, in diesem Fall '--' um die Auskommentierung eines Teils der Query zu verhindern. Auch sollten Strings immer escape-ed werden bevor sie an die Datenbank weitergegeben werden (Funktion db_escape_string($text). An dieser Stelle soll das reichen, es soll ja keine Anleitung zum Hacken werden, aber das macht deutlich wie gefährlich bestimmte Abfragen sein können.
Ergebnisse aus der Datenbank auslesen
/**
* Prüft ob es einen Mitarbeiter mit der UID gibt
*
* @param User-ID des Drupal-System
* @return Array - 0 => 0 = user nicht registriert, 1 = User registriert
* 1 => Integer = Berechtigung des Users
*/
function check_ma($uid)
{
// Prüfen ob der User in der xyz-Datenbank registriert ist und holen der Berechtigung
$query = ' SELECT m.berechtigung, m.name FROM mitarbeiter AS m, abteilungzugehoerig AS a
WHERE m.uid = %d AND m.eintrittsDatum < now() AND (m.austrittsDatum >= now() OR m.austrittsDatum = "0000-00-00")
AND a.uid = %d AND a.active = 1';
$ergDB = db_query($query, $uid, $uid);
$anzahl_erg = db_num_rows($ergDB);
// Wenn kein Ergebniss gefunden wurde
if($anzahl_erg == 0)
return array(0 => 0, 1 => 0);
// Darf nicht passieren - dann ist etwas gewaltig schief gelaufen
elseif($anzahl_erg > 1)
{
drupal_set_message('Suchen Sie den Programmierer und erschlagen Sie ihn.');
return array(0 => 0, 1 => 0);
}
// holen der Ergebnisse
$erg = db_fetch_array($ergDB);
// Rückgabe wenn nichts gefunden wurde
return array(0 => 1, 1 => $erg['berechtigung']);
} // END check_ma()
@atomicx
am 28.04.2008 - 08:41 Uhr
Geht das?:
$erg = db_query('SELECT ip, unixtime FROM {counter} WHERE ip LIKE %s', $ip);
Zum weiterlesen:
http://www.drupalcenter.de/handbuch/6722
luzer schrieb Geht
am 28.04.2008 - 09:06 Uhr
Geht das?:
$erg = db_query('SELECT ip, unixtime FROM {counter} WHERE ip LIKE %s', $ip);
Zum weiterlesen:
http://www.drupalcenter.de/handbuch/6722
Du solltest die Strings in Anführungszeichen setzen
$erg = db_query('SELECT ip, unixtime FROM {counter} WHERE ip LIKE "%s"', $ip);
ansonsten sieht das gut aus (ohne das getestet zu haben).
Gruß
UwBach
Danke, an alle die so
am 28.04.2008 - 13:47 Uhr
Danke, an alle die so schnell geantwortet haben, ich werde es heute nach der Arbeit gleich mal ausprobieren und euch das Ergebnis mitteilen.
Danke :)
Freundliche Grüsse aus der Schweiz, atomicx.
Also ich bekomme immer noch
am 28.04.2008 - 17:46 Uhr
Also ich bekomme immer noch nicht mein gewünschtes Resultat. Es passiert einfach nichts.
echo $erg; == Object id #16
echo 'true'; ==
$erg=db_query('SELECT ip, unixtime FROM {counter} WHERE ip LIKE "%s"', $ip);
echo $erg;
while($a=db_fetch_object($erg)){
$ip=$a->ip;
$unixtime1=$a->unixtime;
echo 'true';
}
Ist es nicht irgendwie möglich einfach den Standart zu nehmen? Also normale Sql-Querys die man sich gewöhnt ist?
Schon versucht, dich langsam
am 28.04.2008 - 19:21 Uhr
Schon versucht, dich langsam vorwärts zu tasten?
Was ergibt:
<?php
$erg = db_query('SELECT ip FROM {counter}');
while ($a = db_fetch_object($erg)){
print $a->ip;
}
?>
um zu sehen ob du die Tabelle überhaupt ansprechen kannst.
Ist die eigentlich in der gleichen DB wie Drupal?
Eigentlich bin ich einer der
am 28.04.2008 - 19:52 Uhr
Eigentlich bin ich einer der Schritt für Schritt arbeitet, was beim Programmieren nicht unklug ist, doch habe ich ja das Script schon getestet bevor ich es in Drupal eingesetzt habe, da funktionierte alles ganz gut.
Nun muss ich das anscheinend noch auf drupalisch Übersetzen, was mir etwas Schwierigkeiten macht, weil ich nicht genau weiss was Drupal noch alles daran ändert bis zum Ziel. Mein Ziel ist es ein Besuchercounter zu basteln der mit Local Shared Objects(Flashcookies) funktioniert und so die Cookies nicht einfach so gelöscht werden.
<?php
$erg = db_query('SELECT ip FROM {counter}');
while ($a = db_fetch_object($erg)){
print $a->ip;
}
?>
Dieser Code funktioniert wunderbar, alle meine Testeinträge von der Spalte "ip" werden aufgeführt.
Ja, diese Tabelle ist in der selben Datenbank wie den Rest von Drupal.
Super jetzt funktioniert
am 28.04.2008 - 21:03 Uhr
Super jetzt funktioniert alles, wie es sollte!
Ich danke euch allen ganz herzlich und wünsche euch noch eine schöne Zeit! Auf bald..