Cum folosim noua extensie MySqli cu PHP

postat acum 3 ani de Stefanescu Mihai in categorie iNoob

Dupa cum deja stiati, PHP a anuntat in 2011 ca extensia MySql va fi deprecated incepand cu versiunea PHP 5.5.0, urmand sa fie scoasa din functie mai apoi. In locul acestei extensii ni se ofera 2 alternative: MySqli (‘i’-ul din coada vine de la ‘improved’) si PDO (PHP Data Objects).

Cu totii stim ca modificarea unui proiect vechi din MySql in MySqli sau PDO poate fi destul de greu si chiar nu stiu ce vom face cu acestea, dar un lucru este sigur…nu trebuie sa mai scriem proiecte noi folosind vechea extensie.

In urma acestei modificari avem si anumite avantaje. De exemplu, PDO este orientat pe obiecte, iar MySqli vine cu suport atat pentru stilul procedural de programare cat si pentru stilul orientat pe obiecte. Ambele vin cu suport pentru prepared statements, tranzactii, si asa mai departe. Si o sa ma intrebati “Dar ce imi trebuie mie prepared statemenets?” .. pai, primul lucru care imi vine acum in minte este faptul ca aceste prepared statements va protejeaza aplicatia impotriva bine cunoscutului procedeu SQL Injection.

Si acum ma veti intreba “Pai si pana la urma eu ce trebuie sa folosesc? MySqli sau PDO?”. Raspunsul scurt ar fii acesta: “Pe care vrei”. Mie imi place sa folosesc MySqli, dar daca aveti nevoie de suport pentru mai multe tipuri de baze de date PDO este solutie ideala.

Cred ca am intins vorba destul si ar fii cazul sa va arat cateva chestii practice. Pentru exemplele de mai jos am sa folosesc extensia mysqli conectata la o baza de date mysql.

Instalarea

Cred ca in primul rand ar trebuii sa vorbim despre instalare…

Aceasta extensie este deja instalata (fie ca vorbim de linux sau windows) pentru ca vine deja instalata cu pachetul php5 mysql.Pentru a o instala pe un server Debian (sau ubuntu) folositi comanda:

apt-get install php5-mysql

Iar pe un Centos (sau Red Hat):

yum install php-mysql

Nu am sa scriu acum cum se poate instala pe toate tipurile de sistem de operare pentru gasiti aici toate instructiunile necesare.

Dupa instalare ar trebuii sa aveti ceva asemanator in phpinfo()

Conectarea

Sa incepem cu definirea parametrilor:

$DBServer = 'server name sau IP'; // de ex: 'localhost' sau '127.0.0.1' sau '192.168.1.100', depinde de serverul votstru
$DBUser   = 'DB_USER';
$DBPass   = 'DB_PASSWORD';
$DBName   = 'DB_NAME';

Conectarea folosind stilul orientat pe obiecte (recomdandat):

$conn = new mysqli($DBServer, $DBUser, $DBPass, $DBName);

// Verificar conexiune
if ($conn->connect_error) {
  trigger_error('Probleme de conectare: '  . $conn->connect_error, E_USER_ERROR);
}

Conectarea in stilul procedural:

*Acest poate fi folosit de incepatorii in ale programarii orientate pe obiecte

$conn = mysqli_connect($DBServer, $DBUser, $DBPass, $DBName);

// verificare conexiune
if (mysqli_connect_errno()) {
  trigger_error('Probleme de conectare: '  . mysqli_connect_error(), E_USER_ERROR);
}

Select

Pentru a folosi comanda de selectie folosim urmatoarea sintaxa:

$sql='SELECT col1, col2, col3 FROM nume_tabel WHERE conditie';

$rs=$conn->query($sql);

if($rs === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
} else {
  $rows_returned = $rs->num_rows;
}

Iterare inregistrari

Folosind numele coloanelor (recomandat):

$rs->data_seek(0);
while($row = $rs->fetch_assoc()){
    echo $row['col1'] . '<br/>';
}

Folosindu-ne de index:

$rs->data_seek(0);
while($row = $rs->fetch_row()){
    echo $row[0] . '<br/>';
}

Salvare valori in array

$rs=$conn->query($sql);

if($rs === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
} else {
  $arr = $rs->fetch_all(MYSQLI_ASSOC);
}
foreach($arr as $row) {
  echo $row['co1'];
}

*Folosind MYSQLI_ASSOC ne este returnat un array asociativ, folosind MYSQLI_NUM ne este returnat un array enumerat, iar MYSQLI_BOTH returneaza ambele tipuri de array

Salvare valori campuri in array

Urmatorul cod ne va returna un array cu primul rand din baza de date (atentie: folosind $rs->data_seek(n) putem returna orice rand dorim)

$rs=$conn->query($sql);

if($rs === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
} else {
  $rs->data_seek(0);
  $arr = $rs->fetch_array(MYSQLI_ASSOC);
}

Numar Randuri

$rows_returned = $rs->num_rows;

 Eliberare memorie

$rs->free();

 Insert

Ne este pusa la dispozitie urmatoarea sintaxa.

real_escape_string este folosit pentru escaping de caractere speae (precum: NUL (ASCII 0), \n, \r, \, ', ", and Control-Z) inainte de a adauga valorile primite de la utilizator in baza de date (pentru a preveni SQL Injection).

$v1="'" . $conn->real_escape_string('col1_value') . "'";

$sql="INSERT INTO tbl (col1_varchar, col2_number) VALUES ($v1,10)";

if($conn->query($sql) === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
} else {
  $last_inserted_id = $conn->insert_id;
  $affected_rows = $conn->affected_rows;
}

Update

Sintaxa pentru update este urmatoarea:

$v1="'" . $conn->real_escape_string('col1_value') . "'";

$sql="UPDATE tbl SET col1_varchar=$v1, col2_number=1 WHERE id>10";

if($conn->query($sql) === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
} else {
  $affected_rows = $conn->affected_rows;
}

Delete

Sintaxa:

$sql="DELETE FROM tbl WHERE id>10";

if($conn->query($sql) === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
} else {
  $affected_rows = $conn->affected_rows;
}

Tranzactii

Avem urmatoarea sintaxa:

try {
  /* Setati autocommit la FALSE. Aceasta comanda incepe tranzactia */
  $conn->autocommit(FALSE);

  $res = $conn->query($sql1);
  if($res === false) {
    throw new Exception('Problema SQL: ' . $sql . ' Error: ' . $conn->error);
  }

  $res = $conn->query($sql2);
  if($res === false) {
    throw new Exception('Problema SQL: ' . $sql . ' Error: ' . $conn->error);
  }

  $res = $conn->query($sql3);
  if($res === false) {
    throw new Exception('Problema SQL: ' . $sql . ' Error: ' . $conn->error);
  }

  $conn->commit();
  echo 'Succes!';

} catch (Exception $e) {

  echo 'Probleme: ' . $e->getMessage();
  $conn->rollback();
}

/* schimbam valoarea lui autocommit */
$conn->autocommit(TRUE);

Conform http://www.php.net/manual/en/mysqli.commit.php#89976, folosind comanda$conn->commit() nu schimbam valoarea lui autocimmit() la TRUE. Ce inseamna asta? inseamna ca orice query scris dupa $conn->commit() va fi resetat la terminarea scriuptului atat timp cat autocommit nu este setat pe TRUE.

ATENTIE: Unele comenzi optiunea commit setata implicit, deci nu pot fi folosite in tranzactie. De exemplu: CREATE TABLE, TRUNCATE TABLE, s.a.m.d

Escaping Strings

Poate ati observat (in acest articol, sau in alta parte) ca inainte de a trimite informatii catre baza de date sunt verificate de caractere speciale (pentru a preveni atacurile SQL Injection)

$safe_string = $conn->real_escape_string($string);

De exemplu: bla"bla\bla va deveni bla\"bla\\bla.

Prepared Statements

Ce sunt aceste Prepared Statements si de ce sunt importante?

Prepared statements sunt folosite impreuna cu o declaratie sql ce poate prelua parametri (folosind diverse simboluri ce tin locul parametrului respectiv, de ex: ? in mysql sau $1 in PostgreSQL, etc).

Dupa ce o declaratie SQL a fost ‘preparata’, SGBD-ul o executa direct, nu mai trebuie sa o recompileze si sa pregateasca un plan de executare. Deci aici vom observa o oarecare optimizare (bineinteles ca aceasta optimizare se observa cel mai bine cand trebuie sa rulam un numar mare de query-uri similare).

Folosind acest procedeu nu mai trebuie sa verificam informatiile (ex: real_escape_string) pentru ca driverul face acest lucru (scade riscul de fi atacati prin SQL Injection).

Hai sa dam cateva exemple:

Select

$sql='SELECT nume, email FROM clienti WHERE id > ? AND numne = ?';
$id_mai_mare = 5;
$nume = 'Ion';

/* Prepare statement */
$stmt = $conn->prepare($sql);
if($stmt === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
}

/* Bind parametrii. Tipuri: s = string, i = integer, d = double,  b = blob */
$stmt->bind_param('is',$id_mai_mare,$nume);

/* Execute statement */
$stmt->execute();

 Iterare rezultate

$stmt->bind_result($nume, $email);
while ($stmt->fetch()) {
  echo $nume. ', ' . $email . '<br>';
}

 Salvare valori intr-un array

$rs=$stmt->get_result();
$arr = $rs->fetch_all(MYSQLI_ASSOC);

 Inchidere statement

$stmt->close();

Insert

$sql='INSERT INTO clienti(nume, prenume) VALUES (?,?)';
$nume = 'Georgescu';
$prenume = 'Ion';

/* Prepare statement */
$stmt = $conn->prepare($sql);
if($stmt === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
}

$stmt->bind_param('ss',$nume,$prenume);

/* Execute statement */
$stmt->execute();

echo $stmt->insert_id;
echo $stmt->affected_rows;

$stmt->close();

Update

$sql='UPDATE clienti SET nume = ?, prenume = ? WHERE id > ?';
$nume = 'Georgescu';
$prenume = 'Ion';
$id_conditie = 5;

/* Prepare statement */
$stmt = $conn->prepare($sql);
if($stmt === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
}

$stmt->bind_param('ssi',$nume,$prenume,$id_conditie);

/* Execute statement */
$stmt->execute();

echo $stmt->affected_rows;

$stmt->close();

Delete

$sql='DELETE FROM clienti WHERE id > ?';
$id_conditie = 5;

/* Prepare statement */
$stmt = $conn->prepare($sql);
if($stmt === false) {
  trigger_error('Problema SQL: ' . $sql . ' Error: ' . $conn->error, E_USER_ERROR);
}

$stmt->bind_param('i',$id_conditie);

/* Execute statement */
$stmt->execute();

echo $stmt->affected_rows;

$stmt->close();

Deconectare (* optional)

$conn->close();

Atat am avut de spus despre mysqli, sper ca ati inteles cat de cat si daca aveti intrebari nu ezitati sa mi le adresati prin rubrica de comentarii.

Sunt un tanar programator din Bucuresti ce lucreaza in PHP/Mysql (MySqli/PDO), Laravel, CodeIgniter, MySQL, PostgreSQL, Wordpress, HTML5/CSS3, Sass, Photoshop si multe altele.
Google+ Community Facebook Group
Acest articol a fost mutat de pe vechea platforma.
Pentru orice eroare aparuta la mutare va rog sa ma contactati!