Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Wangarad 03. 11. 2020, 15:59:02
-
Mam subor core kde je nieco taketo
$mysqli = new mysqli("localhost","root","vertrigo","project");
ak spravim include v inom subore tak mi v pohode funguje
$sql = "SELECT * FROM `test_db`";
$result = $mysqli->query($sql);
ale preco mi to nefunguje pre funkciu?
function calculate($lineID){
$query = "SELECT * FROM `test_db` where id=$lineID";
$result = $mysqli->query($query) or die(mysql_error());
$row = $result->fetch_assoc();
...
vypisuje Undefined variable: mysqli in ....
co robim zle? to musim pre kazdu funkciu pridavat $mysqli = new mysqli("localhost","root","vertrigo","project");?
-
Pred radek $query =... bych dal radek global $mysqli;
-
Pred radek $query =... bych dal radek global $mysqli;
Global? Fuj!
Je třeba předat $mysqli té funkci v parametrech.
-
to bude mrzení.
-
uz je rok 2020, OOP zvlada aj php.
-
Osobně radši používám PDO než mysqli, ale obojí je možné.
https://www.php.net/manual/en/book.pdo.php
Z hlediska bezpečnosti bys měl používat předpřipravené SQL příkazy, jinak ti to někdo lehce může hacknout a vytáhnout data nebo ti smazat databázi.
https://www.w3schools.com/sql/sql_injection.asp
https://www.w3schools.com/php/php_mysql_prepared_statements.asp
A jinak PHP je OOP, tak zkus víc zapojit třídy. Třeba DB wrapper. Něco pro inspiraci:
https://www.itnetwork.cz/php/mvc/objektovy-mvc-redakcni-system-v-php-pdo-crud-wrapped
pak třeba napíšeš:
$db = new Db();
$result = $db->select("SELECT * FROM `test_db` where id=:id",array(":id" => $lineID));
Nevím co píšeš za projekt, ale taky jedna možnost je všechno směřovat zkrz centrální index.php a dynamicky přikládat další php soubory dle potřeby.
A taky používat autoloader tříd (viz spl_autoload_register):
https://www.php.net/manual/en/function.spl-autoload-register.php
Pak nemusíš všude dávat např. include (cesta_k_php_třídě);, ale rovnou vytvoříš nový objekt,např: $db = new DB(); a autoloader ten include udělá sám.
Sice to není přímo odpověď na tvůj dotaz, ale můžeš se tím inspirovat. :-)
-
$db = new Db();
$result = $db->select("SELECT * FROM `test_db` where id=:id",array(":id" => $lineID));
Mně se takový wrapper jeví jako nešikovný. Raději si to napíši jako poctivé 3-4 řádky
$db = new PDO(...);
$sql = "SELECT * FROM `test_db` where id=:id";
$select = $db->prepare($sql);
$select->execute(array("id" => $id));
$result = $select->fetchAll();
A důvod? Každá z těch metod má mnoho volitelných parametrů, pomocí kterých se dá nahradit mnoho vlastností, na které se často používá ORM. Snažit se to natřískat do jednoho wrapperu je cestou do pekel. Navíc se takový prepared statement dá použít opakovaně, což ten wrapper neumí.
V neposlední řadě se to i dobře testuje.
Je ale fakt, že několik wrapperů používám, např.
$db = new MyPDO($config);
$id = $db->insert('User', ['name' => "Kit", 'type' => "admin"]);
Ovšem jak je vidět, tvorba SQL je už zcela ukryta uvnitř. Pokud bych chtěl wrapper na uvedený případ, vypadal by asi takto:
$data = $db->select('test_db', ['id' => $id]);
Ovšem má to spoustu much - například chybí seznam sloupců, jejich přejmenování, není z toho patrné, zda chci pole, dict, anonymní objekt nebo objekt nějaké třídy - prostě to není ono. Pokud bych to chtěl podchytit všechno, bude ovládání složitější, než napsání SQL a stejně to bude umět jen jednoduché dotazy.
-
Asi jsem dal špatný příklad na ten wrapper, radši jsem to měl vypsat sám. Myslel jsem to jako třídu, kde máš obecné funkce. Nezadáváš tam natvrdo SQL příkazy, jen obaluješ funkcionalitu.
Takže budeš mít např:
class Db {
protected $pdo;
protected $statement;
protected $error;
public function __construct() {
try{
$this->pdo = new PDO(DB_DSN . ";dbname=" . DB_NAME .";charset=utf8", DB_USER, DB_PASS));
} catch(Exception $ex){
die("Nelze se spojit s databází!");
}
}
public function select($query,$data) {
try {
$this->statement = $this->pdo->prepare($query);
if ($this->statement->execute($data)) {
return $this->statement->fetchAll();
}
} catch (Exception $e) {
$this->error = $e->getMessage();
}
return null;
}
}
Pak pomocí $db = new Db(); vytvoříš nové spojení s databází
a dotaz provedeš jako $db->select("select * from X where id = :id",array(":id" => $id));
Tedy můžeš vkládat jakkoliv složité sql dotazy a data k nim, není to nijak omezené.
Výhoda je, že nemusíš všude vypisovat to připravování dotazů, jen zavoláš příslušnou funkci. Těch funkcí si tam dáš kolik potřebuješ...minimálně jednu další pro insert/update.
-
K čemu tam máš try...catch? Výjimky nechávám probublat výš právě proto, abych nemusel použít die(). Pokud něco zachytávat, tak PDOException, ale co s ním chceš dělat v takto obecné metodě, kde se ta chyba ani nedá sémanticky popsat? Jedině zanořit do řetězené výjimky.
Nechápu ten return null; na konci. To jako fakt? Na výstupu nečekám null, ale data.
-
Dobre skusme na to ist easy.
Takze mam jeden file kde chcem volat dbconnector.php donho som napchal toto a potom tam napcham query,select,ect..
class DbConnectors extends SystemComponent {
function DbConnector(){
// Load settings from parent class
$settings = SystemComponent::getSettings();
// Get the main settings from the array we've just loaded
$host = 'localhost';
$db = 'T';
$user = 'x';
$pass = 'y';
$conninfo = array('Database'=>$db,'UID'=>$user,'PWD'=>$pass, 'CharacterSet'=>"UTF-8",'ReturnDatesAsStrings'=>true);
$connectionInfo = array( "Database"=>$db, "UID"=>$user, "PWD"=>$pass);
// Connect to the database
$link = sqlsrv_connect($host, $conninfo);
//register_shutdown_function(array(&$this, 'close'));
}
potom mam subor funkcia kde chcem napriklad volat funkciu
<?php
//Include
require_once('DbConnector.php');
function select_test(){
$connector = new DbConnectors();
$sql = "SELECT TOP 10 [data] FROM [test].[dbo].[report] WHERE [Station]= 'xyz' ";
$stmt = sqlsrv_query( $connector, $sql );
ale to mi nefunguje. Preco? Ako by som mal korektne volat spojenie na db?
-
Co znamená "nefunguje"? Nějaké chybové hlášení by nebylo?
-
Array ( [0] => Array ( [0] => IMSSP [SQLSTATE] => IMSSP [1] => -14 [code] => -14 [2] => An invalid parameter was passed to sqlsrv_query. [message] => An invalid parameter was passed to sqlsrv_query. ) )
resp. Warning: sqlsrv_query() expects parameter 1 to be resource, object given
pritom ten isty kod mam inom subore kde je rovno s connectom a tam to funguje ok
-
To bude asi tím, že v $connector nemáš DB resource, ale objekt třídy DbConnector.
Místo toho posledního řádku bych dal
$stmt = $connector->query($sql);
a do třídy DbConnector dopsal metodu
function query($sql) {
return sqlsrv_query($this->link, $sql);
}
Konstruktor DbConnector přejmenuj na __construct a poslední řádek v něm nahraď
$this->link = sqlsrv_connect($host, $conninfo);
-
K čemu tam máš try...catch? Výjimky nechávám probublat výš právě proto, abych nemusel použít die()...
Tak udělat to jde různě. Nechci se s vyjímkama zabývat dále, tak chybu zachytím tady a chybu zapíšu do proměné $error, či do nějakého logu. U funkce pro update se navíc udělá rollback.
Null se vrací pokud došlo k té zachycené chybě, aby bylo jasné, že došlo k chybě (jinak by se provedl ten první return a vrátily se data).
Někde dál v kódu tak můžu mít:
if (!empty($result)) { zobraz data } else { napiš uživateli že došlo k chybě, ať někoho zavolá... } nebo podobně (if result not null...).
Try, catch a die v konstruktoru mám proto, že pokud nepůjde databáze, tak uživatel v mé aplikaci nic neudělá a můžu si dovolit to takhle celé zaříznout. Nejspíš by pak bylo potřeba restartovat celý server.
Je to příklad pro inspiraci. Každý ať si to dělá tak, jak mu to pro daný projekt vyhovuje.
-
Někde dál v kódu tak můžu mít:
if (!empty($result)) { zobraz data } else { napiš uživateli že došlo k chybě, ať někoho zavolá... } nebo podobně (if result not null...).
Takový kód už nepotřebuji právě proto, že výjimka to přeskočí a if by bylo zbytečné, včetně else. Právě zde najde využití blok try...catch.
try {
$result = $db->select($sql);
// zobraz data
} catch (Exception $e) {
// napiš uživateli že došlo k chybě $e, ať někoho zavolá
}
Všimni si, že v $e mám stále kompletní popis chyby i s uvedením místa, kde vznikla. Samozřejmě takové hlášení nepatří uživateli, ale do logu.