mmofacts.com

MySQL: Nur vorhandene Spalten abrufen

gepostet vor 16 Jahre, 11 Monate von kevka
Hi,
ich habe folgendes Problem:
Für mein BG wird der Untergrund in einer Tabelle gespeichert.
Jede Zeile hat eine id und die Spalten sind (bis auf die für die ID) durchnummeriert (S1, S2, S3 usw.)
Jetzt wird der Untergrund mit einer PHP-Datei geladen:

if(isset($_GET["x"]) && $_GET["x"] > 0 && isset($_GET["y"]) && $_GET["y"] > 0 && isset($_GET["h"]) && isset($_GET["w"]))
{
include("../objects/db.php");
$DB = new DB(); //Neues Datenbankobjekt
$sql = new SQLString(); //Neuer SQLString
$XML = "";
$y = 0;
for($i=$_GET["x"];$i<($_GET["x"]+$_GET["w"]);$i++)
{
$a[$y] = "S".$i;
$y++;
}
$sql->setSelect($a, "main_map_static");
$sql->addC("id >=", $_GET["y"], true); //Eine C(ondition) wird hinzugefügt
$sql->addC("id <", $_GET["y"]+$_GET["h"], true);
$DB->run($sql); //Der SQL-String wird ausgeführt
while ($row = $DB->getLine())
{
$XML .= "";
foreach($row as $a)
{
$XML .= "".$a."";
}
$XML .= "";
}
$XML .= "";
$DB->End();//DB schließen
//Header setzten
header("Content-Type: text/xml; charset=UTF-8");
//XML Ausgaben
echo $XML;
}
?>
Der Code funktioniert auch, wenn z.B. $_GET["y"] = 22 und $_GET["h"] = 10 ist, obwohl die höchste ID 22 ist.
Wenn ich jedoch für $_GET["x"] 25 und für die Breite ($_GET["w"]) 10 nehme, erhalte ich eine Fehlermeldung, wahrscheinlich, weil die Spalten, aus denen das Script Daten lesen will einfach nicht existieren.
Doch wie kann ich dieses Problem, ohne eine zusätzlich SQL Abfrage lösen?
MfG Kevka
gepostet vor 16 Jahre, 11 Monate von Macavity
Naja du musst doch selbst wissen wieviele Felder deine Tabelle hat. Felder abfragen die es nicht gibt, wird mit einem Fehler belohnt.
Erstmal würde ich rasch den Einsatz von $variablen empfehlen.
immer $_GET["x"] zu schreiben ist doch etwas nervig, oder nicht?
Einmal $x = $_GET["x"]; und das ist schon etwas kürzer.
Dann noch eine Überprüfung mit rein und es ist wohl noch besser:
$x = (isset($_GET["x"]) && $_GET["x"] > $minSpalte && $_GET["x"] < $maxSpalte) ? $_GET["x"] : 0;
wobei min- und maxSpalte deine kleinsten und größten Spaltenzahlen wären, entsprechend noch y.
gepostet vor 16 Jahre, 11 Monate von Drezil
wieso sollte man überhaupt n spalten für eine n felder breite karte machen?
wieso nicht
x | y | typ | ...

?
und eben nen pk mit quadtree auf x/y
sollte doch viel schneller laufen und man hat das problem mit den dynamischen spalten nicht mehr.
select foo from map where x between 20 and 50 and y between 128 and 258;

PS: $_GET in sql-queries ist grauenhaft.
Wenn $_GET['x'] z.b. "32 and 1=1; drop database game; --" und der string > 0 ist, hast du ein problem (und meines wissens nach ist es > 0, da es auf 32 gecastet wird).
gepostet vor 16 Jahre, 11 Monate von Macavity
Naja er benutzt ja eine Datenbank-Klasse, da vermute ich mal wird schon ein Sicherheitsdeckel sein der solche Inputs verhindert.
Wenn dem nicht so sein sollte, hat Drezil aber absolut Recht.
gepostet vor 16 Jahre, 11 Monate von Nightflyer

32 and 1=1; drop database game;

Und genau deshalb kannst du mySQL-Query keine zwei Anweisungen übergeben. Bin mir nicht mal sicher ob in diesem Fall überhaupt die erste Anweisung ausgeführt würde. Aber drop database geht auf keinen Fall.
gepostet vor 16 Jahre, 11 Monate von kevka
Original von Drezil
und eben nen pk mit quadtree auf x/y
sollte doch viel schneller laufen und man hat das problem mit den dynamischen spalten nicht mehr.
select foo from map where x between 20 and 50 and y between 128 and 258;


Ok, gute Idee.
Ich muss zugeben, dass ich manchmal etwas umständlich denke.
[Edit:]
Warum ist deine Methode eigentlich schneller? (nicht das ich dir nicht vertraue aber es ist immer schön zu wissen warum etwas so ist und nicht nur dass etwas so ist)
Deine Methode benötigt aber etwas mehr Speicher, oder?
Original von Drezil

PS: $_GET in sql-queries ist grauenhaft.
Wenn $_GET['x'] z.b. "32 and 1=1; drop database game; --" und der string > 0 ist, hast du ein problem (und meines wissens nach ist es > 0, da es auf 32 gecastet wird).
Sicher das das funktioniert?
Ich habe mich bis jetzt nur gegen SQl Injects in dieser Form (www.php-faq.de/q/q-sql-injection.html) abgesichert.
MfG Kevka
gepostet vor 16 Jahre, 11 Monate von Lubi
@Nightflyer:
Ich muss dich enttäuschen. Mehrere Queries auf einmal sind machbar (je nach MySQL-Konfiguration). Daher immer Prüfen, ob auch wirklich ganz genau das drin ist, was du erwartest.
Auch ist es sinnvoll zu prüfen, ob Zahlen >= 0 sind, wenn das nötig ist (und natürlich auch, dass es wirklich Zahlen sind!)
@Topic:
Eine normalisierte Datenbank-Struktur ist auf jeden Fall für dieses Problem empfehlenswert, da ansonsten das ganze nicht ordentlich erweiterbar ist (und auch teilweise nicht sinnvoll speicherbar ist)...
gepostet vor 16 Jahre, 11 Monate von Drezil
Original von kevka
Warum ist deine Methode eigentlich schneller? (nicht das ich dir nicht vertraue aber es ist immer schön zu wissen warum etwas so ist und nicht nur dass etwas so ist)
Deine Methode benötigt aber etwas mehr Speicher, oder?

Schneller ist sie nicht zwingend - aber du bist diese dynamisch breiten tabellen los. Mit einer fixen rowwidth kann sql intern noch was optimieren.
Aber der PK mit quadtree ist eigentlich fast genauso fix wie deine lösung - nur eben nicht so umständlich

Original von Drezil

PS: $_GET in sql-queries ist grauenhaft.
Wenn $_GET['x'] z.b. "32 and 1=1; drop database game; --" und der string > 0 ist, hast du ein problem (und meines wissens nach ist es > 0, da es auf 32 gecastet wird).
Sicher das das funktioniert?
Ich habe mich bis jetzt nur gegen SQl Injects in dieser Form (www.php-faq.de/q/q-sql-injection.html) abgesichert.
Bei dem php-mysql-connector hast du das problem (eigentlich) nicht. Nutzt du mysql, dann hast du es. Nutzt du eine andere DB, hast du das problem idR. auch.
@nightflyer: von mysql war vor deinem post keine rede. Ich nutze mysql ohnehin nicht. Bei SQL-Fragen antworte ich also immer mit allen möglichen szenarien. Und selbst wenn das 2. kommando nicht ausgeführt worden wäre, dank dem 1=1 wäre trotzdem eine sql-injection gelungen
gepostet vor 16 Jahre, 11 Monate von Drezil
Original von Drezil
Original von kevka
Warum ist deine Methode eigentlich schneller? (nicht das ich dir nicht vertraue aber es ist immer schön zu wissen warum etwas so ist und nicht nur dass etwas so ist)
Deine Methode benötigt aber etwas mehr Speicher, oder?

Schneller ist sie nicht zwingend - aber du bist diese dynamisch breiten tabellen los. Mit einer fixen rowwidth kann sql intern noch was optimieren.
Aber der PK mit quadtree ist eigentlich fast genauso fix wie deine lösung - nur eben nicht so umständlich

Original von Drezil

PS: $_GET in sql-queries ist grauenhaft.
Wenn $_GET['x'] z.b. "32 and 1=1; drop database game; --" und der string > 0 ist, hast du ein problem (und meines wissens nach ist es > 0, da es auf 32 gecastet wird).
Sicher das das funktioniert?
Ich habe mich bis jetzt nur gegen SQl Injects in dieser Form (www.php-faq.de/q/q-sql-injection.html) abgesichert.
Bei dem php-mysql-connector hast du das problem (eigentlich) nicht. Nutzt du mysql, dann hast du es. Nutzt du eine andere DB, hast du das problem idR. auch.
@nightflyer: von mysql war vor deinem post keine rede. Ich nutze mysql ohnehin nicht. Bei SQL-Fragen antworte ich also immer mit allen möglichen szenarien. Und selbst wenn das 2. kommando nicht ausgeführt worden wäre, dank dem 1=1 wäre trotzdem eine sql-injection gelungen
PS:
wenn ich eine pos. zahl erwarte (was ja die regel ist), dann mach ich
$zahl = abs($_GET['zahl']);

sonste eben nen int-cast. Prüfen muss man die eh noch, aber dann steht wenigstens kein gefährlicher string mehr drin.
gepostet vor 16 Jahre, 11 Monate von kevka
Ich habe jetzt meine Datenbank komplett verändert:

CREATE TABLE map(
x INT,
y INT,
static INT,
objects INT,
temporary INT,
player INT
)
Jetzt noch eine Frage (ihr merkt, mySQL ist nicht gerade meine Stärke):
Wie kann ich am einfachsten mit einer SQL Abfrage die Höhe (den höchste y Wert) und die Breite (den höchste x Wert) ermitteln?
Der für die Hilfe dankende Kevka
gepostet vor 16 Jahre, 11 Monate von raufaser
SELECT MAX( x ), MAX( y ) FROM maptable WHERE 1;
gepostet vor 16 Jahre, 11 Monate von kevka
Danke.
Wie hast du eigentlich deine Karten gespeichert?
gepostet vor 16 Jahre, 11 Monate von raufaser
Bei mir hat jede Karte eine eigene Tabelle in der Datenbank:
x INT
y INT
gfx CHAR
sprite CHAR
lowlevel INT
walkable INT
swimable INT
Und dann gibt es eine Tabelle "map" wo hinterlegt ist, welche Karte in welcher Datenbanktabelle liegt. In einer dritten Tabelle liegen dann die speziellen Feldeigenschaften für die Felder der Karte (z.B. ob auf dem Feld ein NPC ist, oder ein Händler, ein Gasthaus,...).
Gruß,
Marc

Auf diese Diskussion antworten