Fatal error: Call to a member function fetch_assoc() on a non-object
Ik heb de qry ingevoerd in phpmyadmin. Als ik het vraagteken vervang door een waarde, dan werkt het gewoon en geeft hij de juiste gegevens weer.
Code (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
43
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
43
$qry="
SELECT
mw_cursus_onderdeel,
mw_cursus_onderdeel_id,
mw_cursus_datum,
mw_ervaring_groep_naam
FROM
mw_cursus_onderdeel
INNER JOIN
mw_ervaring_groep
ON
mw_cursus_onderdeel_groep=mw_ervaring_groep_id
INNER JOIN
mw_cursus
ON
mw_cursus_onderdeel=mw_cursus_onderdeel_id
WHERE
mw_cursus_persnr=?
AND
mw_cursus_onderdeel_rechten=1
";
$statement = $connection->prepare($qry);
$statement->error; //var_dump($statement);
$statement->bind_param('i', $_GET['mw_id']);
$statement->execute();
$statement->store_result();
var_dump($statement);
$row_cnt = $statement->num_rows;
$result = $statement->get_result();
if($row_cnt == 0)
{
}
if($row_cnt >= 1)
{
}
while($basis = $result->fetch_assoc()){
}
SELECT
mw_cursus_onderdeel,
mw_cursus_onderdeel_id,
mw_cursus_datum,
mw_ervaring_groep_naam
FROM
mw_cursus_onderdeel
INNER JOIN
mw_ervaring_groep
ON
mw_cursus_onderdeel_groep=mw_ervaring_groep_id
INNER JOIN
mw_cursus
ON
mw_cursus_onderdeel=mw_cursus_onderdeel_id
WHERE
mw_cursus_persnr=?
AND
mw_cursus_onderdeel_rechten=1
";
$statement = $connection->prepare($qry);
$statement->error; //var_dump($statement);
$statement->bind_param('i', $_GET['mw_id']);
$statement->execute();
$statement->store_result();
var_dump($statement);
$row_cnt = $statement->num_rows;
$result = $statement->get_result();
if($row_cnt == 0)
{
}
if($row_cnt >= 1)
{
}
while($basis = $result->fetch_assoc()){
}
de var dump geeft dit weer, weet niet precies wat het betekend
object(mysqli_stmt)#9 (10) {
["affected_rows"]=> int(3)
["insert_id"]=> int(0)
["num_rows"]=> int(3)
["param_count"]=> int(1)
["field_count"]=> int(4)
["errno"]=> int(0)
["error"]=> string(0) ""
["error_list"]=> array(0) { }
["sqlstate"]=> string(5) "00000"
["id"]=> int(7) }
Gewijzigd op 16/02/2015 01:18:54 door J C
=> mysqli_stmt::bind_param Returns TRUE on success or FALSE on failure.
=> mysqli_stmt::execute Returns TRUE on success or FALSE on failure.
=> mysqli::store_result Returns a buffered result object or FALSE if an error occurred.
Hoewel al deze bovenstaande functies (of beter methods) allemaal iets teruggeven doe jij daar helemaal niets mee.
Kun je me aangeven wat ik er mee zou kunnen doen? Ik heb een aantal tutorials gevolgd over mysqli, maar de meeste geven aan dat ik het zo zou moeten doen.
Het is eigenlijk een algemeen verhaal. Functies - eigen gemaakte of standaard PHP - kunnen een waarde retouneren:
Code (php)
Zo dus ook de bovengenoemde functies.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$statement = $connection->prepare($qry);
if(!$statement)
echo 'mysqli::prepare gaf FALSE terug!';
$statement->error; //var_dump($statement);
if(!$statement->bind_param('i', $_GET['mw_id']))
echo 'mysqli_stmt::bind_param gaf FALSE terug!';
if(!$statement->execute())
echo 'mysqli_stmt::execute gaf FALSE terug!';
?>
$statement = $connection->prepare($qry);
if(!$statement)
echo 'mysqli::prepare gaf FALSE terug!';
$statement->error; //var_dump($statement);
if(!$statement->bind_param('i', $_GET['mw_id']))
echo 'mysqli_stmt::bind_param gaf FALSE terug!';
if(!$statement->execute())
echo 'mysqli_stmt::execute gaf FALSE terug!';
?>
en bij statement store_result gaat het helemaal fout want deze functie geeft het resultaat terug en die heb je dus nodig voor verdere verwerking
Code (php)
Gewijzigd op 16/02/2015 10:17:06 door Frank Nietbelangrijk
Is er een specifiek reden waarom je deze variant hebt verkozen boven het alternatief ((real_)query() icm escapen DATA-delen en filteren van invoer) die, naar mijn mening, schonere (en zeker kortere) code oplevert?
Zeker als de enige parameter $_GET['mw_id'] is in de query en deze nummeriek is zou ik gaan voor intval($_GET['mw_id']) en mysql injection is onmogelijk.
Het gebruik van intval is naïef.
Thomas van den Heuvel op 16/02/2015 12:22:52:
Persoonlijk zou ik geen prepared statements gebruiken in combinatie met MySQLi mede (maar niet uitsluitend) omdat je code wolliger wordt, wat de kans op fouten vergroot. Ook het debuggen kost dan vervolgens meer tijd.
Is er een specifiek reden waarom je deze variant hebt verkozen boven het alternatief ((real_)query() icm escapen DATA-delen en filteren van invoer) die, naar mijn mening, schonere (en zeker kortere) code oplevert?
Is er een specifiek reden waarom je deze variant hebt verkozen boven het alternatief ((real_)query() icm escapen DATA-delen en filteren van invoer) die, naar mijn mening, schonere (en zeker kortere) code oplevert?
uhm, om heel kort, maar niet onbeleefd te zijn, omdat ik geen idee heb waar je het over hebt. De bovenstaande methode wordt als veilige manier in de tutorials omschreven.
Als je je bedient van een aantal simpele regels dan kun je MySQLi ook op een veel eenvoudigere manier gebruiken dan al die bovenstaande mumbo jumbo.
prepare
bind_param
execute
store_result
get_result
voor één SELECT query?
Ain't nobody got time for that.
Zeker waar, ik zat me er al behoorlijk aan te ergeren dat iets wat vernieuwend zou moeten zijn nu zoveel extra werk moet kosten.
Gewijzigd op 18/02/2015 19:46:12 door J C
Om hier vast een beetje op die PM vooruit te lopen: gebruik een wrapper class zodat je database-specifieke functies/methoden niet hardcode. Dit, in combinatie met een aantal vuistregels voor veilige queries, zorgen voor een (m.i.) stuk eenvoudiger gebruik.
Bovenstaande code zou er dan als volgt uit komen te zien:
Code (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
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
<?php
// filter input
$medewerkerId = false;
// preg_match of filter_var als je dat leuker vindt
// andere functies lijken mij ongeschikt vanwege typecasting
if (preg_match('#^[1-9][0-9]*$#', $_GET['mw_id'])) {
$medewerkerId = trim($_GET['mw_id']);
}
if ($medewerkerId === false) {
// ongeldig medewerker id
// ...
} else {
// $db->query throwt een exception als de query een fout oplevert
// hier zou dus nog ergens een try-catch omheen moeten
// in deze query is het escapen van $medewerkerId alleen bedoeld voor
// het markeren van een DATA-deel - de escaping zelf doet verder niets in dit geval
$res = $db->query(
'SELECT mw_cursus_onderdeel, mw_cursus_onderdeel_id, mw_cursus_datum, mw_ervaring_groep_naam
FROM mw_cursus_onderdeel
INNER JOIN mw_ervaring_groep ON (mw_cursus_onderdeel_groep = mw_ervaring_groep_id)
INNER JOIN mw_cursus ON (mw_cursus_onderdeel = mw_cursus_onderdeel_id)
WHERE mw_cursus_persnr = '.$db->escape($medewerkerId).'
AND mw_cursus_onderdeel_rechten = 1'
);
if ($res->numRows() > 0) {
// loop door resultaten
while ($row = $res->fetchAssoc()) {
// doe iets met $row
// ...
}
} else {
// geen resultaten
// ...
}
// geef resultaat vrij
$res->freeResult();
}
?>
// filter input
$medewerkerId = false;
// preg_match of filter_var als je dat leuker vindt
// andere functies lijken mij ongeschikt vanwege typecasting
if (preg_match('#^[1-9][0-9]*$#', $_GET['mw_id'])) {
$medewerkerId = trim($_GET['mw_id']);
}
if ($medewerkerId === false) {
// ongeldig medewerker id
// ...
} else {
// $db->query throwt een exception als de query een fout oplevert
// hier zou dus nog ergens een try-catch omheen moeten
// in deze query is het escapen van $medewerkerId alleen bedoeld voor
// het markeren van een DATA-deel - de escaping zelf doet verder niets in dit geval
$res = $db->query(
'SELECT mw_cursus_onderdeel, mw_cursus_onderdeel_id, mw_cursus_datum, mw_ervaring_groep_naam
FROM mw_cursus_onderdeel
INNER JOIN mw_ervaring_groep ON (mw_cursus_onderdeel_groep = mw_ervaring_groep_id)
INNER JOIN mw_cursus ON (mw_cursus_onderdeel = mw_cursus_onderdeel_id)
WHERE mw_cursus_persnr = '.$db->escape($medewerkerId).'
AND mw_cursus_onderdeel_rechten = 1'
);
if ($res->numRows() > 0) {
// loop door resultaten
while ($row = $res->fetchAssoc()) {
// doe iets met $row
// ...
}
} else {
// geen resultaten
// ...
}
// geef resultaat vrij
$res->freeResult();
}
?>
Er zijn overigens 1001 manieren om hier invulling aan te geven. Ik heb mijn manier, jij hebt jouw manier. Ik kan mij dan ook voorstellen dat iemand anders iets compleet anders doet. Voor alles wat ik hierboven doe heb ik in ieder geval een reden die ik kan motiveren dus voordat je roept "dat is fout" of wat dan ook, vraag je eerst eens af waarom ik dit zo doe.
Deze "set" tezamen levert voor zover ik kan overzien een veilige werkwijze op, en daar was het volgens mij allemaal om begonnen (en wat dat betreft heiligt dat mijn middelen).
EDIT: $_GET['mw_id'] i.p.v. $_GET['id']
EDIT: het meta-karakter "$" accepteert ook een newline, dus je zou het resultaat van de match ook nog kunnen trimmen om er verzekerd van te zijn dat de newline wordt verwijderd
Gewijzigd op 18/02/2015 20:21:30 door Thomas van den Heuvel
Ziet er wel goed uit, ik kende de freeresult functie nog niet. Alleen de close functie.
De bovenstaande functies ($db->query, $db->escape, $res->numRows(), $res->fetchAssoc(), $res->freeResult()) zijn geen standaard PHP, die zitten in zelfgeschreven PHP-klasses.