Autor | Zpráva | ||
---|---|---|---|
Chuchycek Profil |
Zdravím,
píšu si vlastní databázovou třídu a narazil jsem na problém, nevím jak vhodně napsat funkci na WHERE. Výběry sloupců jsem vyřešil takto: private function rowsArray(array $array) { $num = count($array); if ($num == 0) { $data = "*"; } else { for ($i = 0; $i < $num; $i++) { $data .= $this->realEscape($array[$i]); if ($i < ($num - 1)) { $data .= ", "; } } } return $data; } Třída pro select: public function select($table, array $row = NULL, $where = "", $order = "", $type = "assoc") { if ($this->existTable($table)) { $rows = $this->rowsArray($row); $where = $this->whereArray($where); $query = "SELECT " . $rows . " FROM " . $table . " " . $where . " " . $order; return $this->returnArray($query, $type); } else { return false; } } A jelikož chci mít i v funkci whereArray() ošetřený každý vstup pomocí mysql_real_escape_string(), tak si nevím rady, jak to udělat, conejefektivněji. Děkuji za každou radu, která mě posune dál. Prosím přesunout do kategorie PHP. |
||
Tori Profil |
#2 · Zasláno: 14. 10. 2012, 11:35:41 · Upravil/a: Tori
Metoda realEscape zajišťuje i zpětné apostrofy okolo názvů sloupců?
K metodě rowsArray: možná by bylo přehlednější místo cyklu použít array_map + implode. Ad whereArray: jaký vstup chcete zpracovávat? pole [sloupec => hodnota]? Pokud bude víc hodnot tak jak rozlišíte mezi AND a OR (myslím jak to napíšu, když budu volat metodu select)? Trochu mi tam nesedí 5.parametr - $type, protože se netýká dotazu ale získávání dat. Buď bych ho dala do jiné metody, která získává data, anebo select přejmenovala. Spíš to první, kvůli single responsibility. Ještě k té metodě realEscape: tím "real" naznačuje, že se bude chovat jako mysql_real_escape_string, tzn. že je určena jen pro řetězce. Přitom ji ale používáte pro názvy sloupců, kde bych čekala spíš metodu escapeIdentifier nebo tak něco. |
||
Chuchycek Profil |
#3 · Zasláno: 14. 10. 2012, 11:54:03
Ano realEscape zajištuje SQL injection.
U whereArray jsem původně taky myslel pole, jenže když tam bude více hodnot, tak jak to udělat co nejefektivněji, kvůli AND a OR, taky jsem zamýšlel, že to nechám jako string a potom vše, co bude v uvozovkách ošetřím, jenže to se mi zdá, že by to mohlo být lehce napadnutelné. Ten 5. paramatr si myslím, že je v pořádku, když není povinný... |
||
Tori Profil |
#4 · Zasláno: 14. 10. 2012, 12:42:40
Chuchycek:
A co třeba takováhle syntax? První položka pole, která má číselný klíč, určuje typ spojení. (Tzn. nemůžu odkazovat na vybrané sloupce pořadím, ale jen aliasem). # pokud typ není zadaný, použije se implicitně OR $where = array('col1' => 'value1', 'col2' => 'value2'); -> "`col1` = 'value1' OR `col2` = 'value2' # stejný výsledek jiným zápisem $where = array('OR', 'col1' => 'value1', 'col2' => 'value2'); # nebo $where = array('col1' => 'value1', 'col2' => 'value2', 'OR'); # více skupin podmínek se zapíše jako několik vnořených polí $where = array( 'OR', array('AND', 'col1' => 'value1', 'col2' => 'value2'), array('col3' => 'value3') ); -> "(`col1` = 'value1' AND `col2` = 'value2') OR (`col3` => 'value3')" Kromě AND a OR by mohl být další typ návěští (anebo specielní klíč místo názvu sloupce?), pokud byste chtěl zadat nějakou SQL funkci apod. (jako modifikátor %sql v dibi). Ale je to jen nápad, co by mi připadalo snadno zapamatovatelné na používání, sama jsem DB vrstvu nikdy nezkoušela psát. |
||
Chuchycek Profil |
Tak jsem napsal jednu z možností a narazil jsem ještě na problém s výrazy v dotazu. Napadlo mě ještě todle, ale nejsem si jistý, jestli to je nejkvalitnější řešení..
//$where = array('col1' => 'value1', 'col2' => 'value2.!=', 'OR'); private function whereArray($array) { $num = count($array); if ($num == 0) { $data = ""; } else { foreach ($array as $key => $value) { if ($key != 0) { $result = explode(".", $value); if (cout($result) == 1) { $equals = "="; } else { $equals = $result[1]; } $data .= $key . $equals . "'" . $this->realEscape($result[0]) . "'"; } else { $data .= " " . $value . " "; } } } return $data; } |
||
peta Profil |
#6 · Zasláno: 15. 10. 2012, 10:12:25
foreach ($values as $key=>$value) { $key = mysql_real_escape_string($key); $where[] = "`$key`=" . $this->escape($value); } $where = implode(' AND ',$where); U selectu where vubec neresim, protoze tam obvykle muze byt jakekoliv. U insertu, update a delete obvykle pouzivam jen AND. Updatuji a deletuji vetsinou jen vuci id. |
||
panther Profil |
#7 · Zasláno: 15. 10. 2012, 10:16:38
Chuchycek:
jestli dobre chapu, teckou u hodnoty oddelujes rovnost a nerovnost (= vs. !=)? Pokud ano, rozhodne to dobre navrhnute/vymyslene nemas. Nenapada te, kdy se to zacne hroutit? |
||
Chuchycek Profil |
panther:
Ano, to mě taky napadlo a proto jsem taky píšu ohledně nejlepšího řešení. A hlavně je to jen takový první nápad, co se mi dostal do hlavy.. |
||
panther Profil |
#9 · Zasláno: 15. 10. 2012, 15:26:10
Chuchycek:
staci, aby v hodnote ukladane do sloupce byla tecka. Treba ve vete, desetinnem cisle, ... Asi bych osobne vychazel z toho, co napsala Tori, tzn. vkladat jednotlive rozdilne useky do poli, porovnani (ne)rovnosti by pak musel byt dalsi parametr v kazdem tom poli, s defaultnim „rovna se“. |
||
Chuchycek Profil |
#10 · Zasláno: 15. 10. 2012, 15:41:30
panther
ano to vím, že je to chybné, ale říkal jsem, že to byl první nápad. Taky bych tam místo tečky mohl dát nějakou kombinaci znaků..., ale o tom zase jiná. Vycházím z toho co napsala Tori a nejspíš to bude asi nejlepší řešení, přdat do pole ještě jeden parametr navíc a nebo jak psal Peta, vůbec where neřešit.. |
||
panther Profil |
#11 · Zasláno: 15. 10. 2012, 15:42:44
Chuchycek:
„Taky bych tam místo tečky mohl dát nějakou kombinaci znaků...“ ani kombinaci... zhrouti se ti to vzdy, kdyz bude nekdo tuto sekvenci znaku, byt sebeodpudivejsi, chtit vlozit. Na toto slouzi parametry, ne retezeni stringu pomoci nejakych pochybnych separatoru. |
||
peta Profil |
Ja bych neresil cely select. Mam v ruznych projektech tak komplikovane where podminky, ze by to tvym systemem asi tezko proslo. A v jinych zas pouzivam kombinace s JOIN nebo propojeni 4 selectu pomoci UNION. Nastesti na to mame db specialistu, sam bych asi tak slozity dotaz neposkladal (asi 300 radku).
|
||
Chuchycek Profil |
peta
Ano, už nad tím taky přemýšlím, že vyřešit celý select, je komplikovanější než jsem čekal, ještě se s tím zkusím trošku poprat a uvidím jestli nezůstanu u úpravy jen části dotazu. Teď jsem where vymyslel takto: //$where = array('col1' => array("value1"), 'OR', 'col2' => array('value2', "!=")); private function whereArray($array) { if (count($array) == 0) { $data = ""; } else { $data = "WHERE "; foreach ($array as $key => $val) { if (is_int($key)) { $data .= " " . $val . " "; } else { if (!isset($val[1])) { $comparison = "="; } else { $comparison = $val[1]; } $data .= $key . $comparison . "'" . $this->realEscape($val[0]) . "'"; } } } return $data; } Ještě bych prosil o komentář k výběru tabulky, popř. spojováním tabulek s INNER JOIN, je to opět takový první nápad, co jsem dostal. //vstup retezec nebo pole $tables = array('table1' => 't1', 'table2' => 't2', 't1.id=t2.kdo'); private function tables($tables) { $data = "FROM "; if (!is_array($tables)) { if ($this->existTable($tables)) { $data .= $this->dbindex . $table; } else { $data = false; } } else { $noTable = false; $firstTable = true; $firstON = true; foreach ($tables as $key => $val) { if (is_int($key)) { if ($firstON) { $data .= " ON " . $val . ""; $firstON = false; } else { $data .= ", " . $val . ""; } } else { if ($this->existTable($key)) { if ($firstTable) { $data .= $this->dbindex . $key . " " . $val; $firstTable = false; } else { $data .= " INNER JOIN " . $this->dbindex . $key . " " . $val; } } else { $noTable = true; } } } if ($noTable) { $data = false; } } return $data; } |
||
Tori Profil |
Chuchycek:
Pěkně se to klube. :) Jestli můžu ještě pár poznámek: Podle [#13] musím psát operátor (OR, AND) vícekrát, mezi každé dvě hodnoty. Šlo by to i tak, abych ho napsala jen jednou, v libovolném pořadí (napovím: $where = 'WHERE '.implode($operator, $podminky); )
V [#5] jste měl dobrý nápad rozlišovat operátory podle toho, že mají klíč 0, k tomu bych se ještě vrátila. Akorát potřebujete rozlišit stavy: - $pole[0] obsahuje operátor porovnání array("sloupec" => "hodnota", '=')
- $pole[0] obsahuje logický operátor array("sloupec" => "hodnota", "sloupec2" => "hodnota2", 'OR')
- $pole[0] obsahuje nadbytečný log.operátor, který se má ignorovat array("sloupec" => "hodnota", 'AND')
- $pole[0] neobsahuje operátor, ale řetězec = chyba array("sloupec" => "hodnota", 'hodnota2')
A možná by nebylo špatné místo přímého zápisu operátorů jako řetězců používat konstanty třídy: DB::LT, DB::LTE, DB::EQ, DB::NONEQ, DB::AND, ...
panther: „Na toto slouzi parametry, ne retezeni stringu pomoci nejakych pochybnych separatoru.“ Na druhou stranu jedna známá DB vrstva zrovna toto používá, akorát přilepuje řetězec k názvu sloupce (kde to imho nemůže ničemu vadit, pokud oddělovačem nebude tečka). ;-) Ale stejně jako tam bych to nepoužívala pro operátory, ale spíš jako návěští, že zadaná hodnota je něco jiného než řetězec (např. přímo zadaný SQL kód, název jiného sloupce, logická/nulová hodnota...), protože to ta escapovací metoda sama nemá šanci poznat. |
||
Chuchycek Profil |
#15 · Zasláno: 17. 10. 2012, 22:04:54
Možná jsem to dobře nepochopil s těmi stavy, ale není to trošku zbytečné, když budu kontrolovat, jestli mám dobře vyplněné pole?
|
||
Časová prodleva: 12 let
|
0