Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP] Functie maken voor het uitvoeren van een MySQL query

Pagina: 1
Acties:

  • Joep
  • Registratie: December 2005
  • Laatst online: 21-11 19:06
Beste tweakers,

Ik ben bezig met php te doorgronden en ben ondertussen bezig met een simpele testsite gekoppeld met een MySQL-database. Ik moet nu zo vaak queries uitvoeren, dat ik er een functie voor wil maken, zodat ik niet elke keer de hele functie moet typen, maar gewoon de functie kan aanroepen.

Dit is de situatie nu:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$connect = mysqli_connect("localhost", "root", "derpderp", "databeest");
if (mysqli_connect_errno())
{
    echo 'Failed to connect to MySQL: ' . mysqli_connect_error();
}
$result = mysqli_query($connect, "SELECT * FROM users ORDER BY last_name");

echo '<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Phone number</th>
<th>Email address</th>
</tr>';

while($row = mysqli_fetch_array($result))
{
    echo '<tr>';
    echo '<td>' . $row['id'] . '<td>';
    echo '<td>' . $row['first_name'] . ' ' . $row['last_name'] . '</td>';
    echo '<td>' . $row['phone_number'] . '</td>';
    echo '<td>' . $row['email_address'] . '</td>';
    echo '</tr>';
}
echo '</table>';

mysqli_close($connect);


Dit is mijn poging tot het maken van een funtie:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function execute($query) {
$connect = mysqli_connect("localhost", "root", "derpderp", "databeest");
if (mysqli_connect_errno())
{
    echo 'Failed to connect to MySQL: ' . mysqli_connect_error();
}
$result = mysqli_query($connect, $query);
mysqli_close($connect);
return $result;
}

$result = execute("SELECT * FROM users ORDER BY last_name");

echo '<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Phone number</th>
<th>Email address</th>
</tr>';

while($row = mysqli_fetch_array($result))
{
    echo '<tr>';
    echo '<td>' . $row['id'] . '<td>';
    echo '<td>' . $row['first_name'] . ' ' . $row['last_name'] . '</td>';
    echo '<td>' . $row['phone_number'] . '</td>';
    echo '<td>' . $row['email_address'] . '</td>';
    echo '</tr>';
}
echo '</table>';


Hoewel het goed gaat/lijkt te gaan, heb ik er zo m'n bedenkingen bij. Ik sluit de connectie met de database nog voordat ik in regel 22 verder ga met mysqli_fetch_array($result). Mag dat? Kan dat? (schijnbaar wel) Hoe kan dat netter/beter?

Daarnaast vraag ik me af of ik misschien code teveel heb geschreven. Ik heb het vermoeden dat ik teveel constantes definieer en dat ik een regel code teveel heb getypt. Hoe kan dit netter/beter?

  • jessy100
  • Registratie: November 2010
  • Laatst online: 21-11 14:43
Ziet er opzich prima uit. Natuurlijk ben ik verplicht er bij te melden dat je script vatbaar is voor SQL-injecties. Verder is de code niet heel verkeerd. Om het wat effectiever te maken kun je het volgende doen:

code:
1
Return mysqli_query($query);


ipv

code:
1
2
$result = mysqli_query($query);
Return $result;


Verder kun je ook kijken naar de OO variant van mysqli, dit is nog nettere en duidelijkere code.

Voorbeeldje:
code:
1
2
3
4
5
6
7
$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: " . $mysqli->connect_error;
}

$res = $mysqli->query("SELECT * FROM users");
$row = $res->fetch_assoc();


als je de OO variant gebruikt hoef je niet bij elke functie de connectie opnieuw mee te geven. Dit werkt veel fijner naar mijn mening.

De connectie closen kun je het best alleen doen als je zeker weet dat de connectie niet meer aangeroepen gaat worden. Een connectie openen kost resources. Dus meerdere keren in het zelfde script een connectie openen kost meer memory dan de connectie open laten. Php sluit open db connecties zelf aan het eind van het script.

En ja, je mag mysqli_fetch_array gebruiken nadat de connectie gesloten is. Deze functionaliteit in niet afhankelijk van connectie maar van php zelf.

[ Voor 57% gewijzigd door jessy100 op 11-05-2014 17:26 ]


  • Biersteker
  • Registratie: Juni 2009
  • Laatst online: 20-11 17:34
Ik zou altijd beginnen met de view en de data uit elkaar te halen.
Voorbeeld (DISCLAIMER: Puur voor het idee.)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
$query = "SELECT * FROM users ORDER BY last_name";
$db = New database;
$view = New view;
$view->DrawTable($db->execute($query));


class database(){
    public function __construct(){
    $connect = mysqli_connect("localhost", "root", "derpderp", "databeest"); 
    if (mysqli_connect_errno()) {
        echo 'Failed to connect to MySQL: ' . mysqli_connect_error(); 
            }        
        }
        public function execute($query) { 
            return $connect->query($query); 
        }
        public function __destruct(){
            mysqli_close($connect); 
        }
    }
class view(){

    function DrawTable($result){
    echo '<table border="1"><tr> 
    <th>ID</th> 
    <th>Name</th> 
    <th>Phone number</th> 
    <th>Email address</th> 
    </tr>'; 

    while($row = mysqli_fetch_array($result)) 
    { 
    echo '<tr>'; 
    echo '<td>' . $row['id'] . '<td>'; 
    echo '<td>' . $row['first_name'] . ' ' . $row['last_name'] . '</td>'; 
    echo '<td>' . $row['phone_number'] . '</td>'; 
    echo '<td>' . $row['email_address'] . '</td>'; 
    echo '</tr>'; 
    } 
    echo '</table>'; 
 };


Maar als je het echt netjes zou willen doen, zou je eigenlijk naar class extends mysqli moeten kijken.
Bijvoorbeeld : http://www.blrf.net/blog/...ysqli-class-with-example/

@hierboven
jessy100 schreef op zondag 11 mei 2014 @ 16:20:
Ziet er opzich prima uit. Natuurlijk ben ik verplicht er bij te melden dat je script vatbaar is voor SQL-injecties.
Waar zie je SQL-injection dan? 8)7
SELECT * FROM users ORDER BY last_name ?
Er is geen userinput in de query zo te zien. een htmlentities() erover wel nuttig zijn. Maar weinig mogelijkheid to ' OR '1=1' input ;)

[ Voor 21% gewijzigd door Biersteker op 11-05-2014 17:00 ]

Originally, a hacker was someone who makes furniture with an axe.


  • C0rnelis
  • Registratie: Juni 2010
  • Laatst online: 01-11 21:54
jessy100 schreef op zondag 11 mei 2014 @ 16:20:
...
Natuurlijk ben ik verplicht er bij te melden dat je script vatbaar is voor SQL-injecties.
...
Mijn persoonlijke ervaring is dat het gebruik van PDO i.c.m. prepared statements hierin verreweg de gemakkelijkste oplossing is. Door alle noodzakelijke function-calls weer in een losse functie te stoppen krijg ik bijv. code als:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// $db is een php class http://pastebin.com/TYupNLQd

function do_query( $sql, $params = null ) {
    global $db;
        
    $statement_handler = $db->prepare( $sql );
    
    if( isset( $params ) ) {
        $statement_handler->execute( $params );
    } else {
        $statement_handler->execute();
    }
        
    return $statement_handler;
}

$user_sth = do_query( 'SELECT * FROM user WHERE id = ?', array( current_user_id() ) );
$user = $user_sth->fetch();


Ik ben ook groot fan van de optie PDO::FETCH_OBJ

Zelf gebruik ik tegenwoordig voor kleinere projecten RedBean's ORM.

  • jessy100
  • Registratie: November 2010
  • Laatst online: 21-11 14:43
@biersteker right.. zondag morgen eh.

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 21-11 14:12
Ik zou ook kijken naar een ORM, tenzij je het doet ter leering ende vermaeck.

Ik gebruik zelf Eloquent (Laravel Database component):

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;

$capsule->addConnection([
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'database',
    'username'  => 'root',
    'password'  => 'password',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
]);

// Query Builder
$users = Capsule::table('users')->orderBy('last_name', 'asc')->get();
// Of
$results = Capsule::select('select * from users where id = ?', array(1));

// Of Eloquent ORM
class User extends Illuminate\Database\Eloquent\Model {}
$users = User::orderBy('last_name', 'asc')->get();

echo '<table border="1"> 
<tr> 
<th>ID</th> 
<th>Name</th> 
<th>Phone number</th> 
<th>Email address</th> 
</tr>'; 

foreach($users as $user)
{ 
    echo '<tr>'; 
    echo '<td>' . $user->id . '<td>'; 
    echo '<td>' . $user->first_name . ' ' . $row['last_name'] . '</td>'; 
    echo '<td>' . $user->phone_number . '</td>'; 
    echo '<td>' . $user->email_address . '</td>'; 
    echo '</tr>'; 
}

[ Voor 74% gewijzigd door Barryvdh op 12-05-2014 08:53 ]


  • BikkelZ
  • Registratie: Januari 2000
  • Laatst online: 21-02 08:50

BikkelZ

CMD+Z

+1 voor PDO
+1 voor het uit elkaar halen (dus niet eens in de zelfde file voorkomen) van DB code en view code.

PHP is een prima template taal maar alle logica die je leest moet wel gebeuren in de code en niet tussen je view door. Ook moet je view uit HTML bestaan met wat PHP er tussendoor en niet uit echo's, dat is makkelijker voor een designer, zelfs als je zelf de designer bent.

Misschien is het makkelijker om een basis klasse te maken voor CRUD en die dan steeds te extenden per model object wat je nodig hebt. Dus User extends DatabaseItem.

Aan de andere kant zijn er al bergen mensen die dit soort dingen hebben gebouwd.

iOS developer


  • xh3adshotx
  • Registratie: Oktober 2011
  • Laatst online: 28-02-2023
Om terug te komen op je originele code:

PHP:
1
2
3
4
5
6
7
<?php 
function execute($query) { 
$connect = mysqli_connect("localhost", "root", "derpderp", "databeest"); 
if (mysqli_connect_errno()) 
{ 
    echo 'Failed to connect to MySQL: ' . mysqli_connect_error(); 
}


Het is natuurlijk helemaal niet nodig om elke keer een nieuwe connectie te maken. Zorgt alleen maar voor onnodige overhead, want je kan gewoon meerdere queries per connectie uitvoeren. Je connectie hoef je pas aan het eind van je script te sluiten, het kan eerder maar helemaal als je meerdere queries per connectie doet is dat niet handig. Zoals eerder gezegd kan je nog beter met OOP MySQLi werken of PDO.

In jouw code controleer je of de verbinding mislukt is (goed), maar daarna ga je gewoon door met het uitvoeren van een query (fout). Je moet dus wel iets doen met de error i.p.v het alleen maar weergeven.

Je hoort je HTML te scheiden van je code, maar om te leren is het niet erg om het in het begin door elkaar te doen zolang je je maar realiseert dat het niet zo "mag". Wees je er ook van bewust dat als er nu een gebruiker is met de voornaam:

JavaScript:
1
<script>alert("Hoi, ik ben een klootzak");</script>


Dat je door jouw code, bij het bekijken van de pagina, een mooie alert te zien krijg. Een alert is nog niet zo vervelend, maar het word vervelender als je cookies ga stelen of een redirect naar een foute website uitvoert. Gebruik daarom htmlentities

[ Voor 12% gewijzigd door xh3adshotx op 12-05-2014 16:03 ]


  • Joep
  • Registratie: December 2005
  • Laatst online: 21-11 19:06
Bedankt voor de reacties! PDO, ORM, OO en sanitizen komt nog. Ik wil eerst de absolute basis van PHP leren. Waar ik wel benieuwd naar ben is hoe je de html en de php kunt splitsen.

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 21-11 14:12
Je kan gebruik maken van een template engine, bijvoorbeeld http://platesphp.com of http://twig.sensiolabs.org
Ik vond deze serie wel interessant, niet echt basis maar legt wel wat veel voorkomende dingen uit voor als je dingen zelf wil doen: http://fabien.potencier.o...ymfony2-components-part-1
Pagina: 1