Fatal error: Call to a member function fetch_assoc() on a non-object

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

J C

J C

16/02/2015 01:12:39
Quote Anchor link
Ik zit te stoeien met een query. Volgens mij geeft de foutmelding aan dat de query niet klopt, maar ik kan de fout niet vinden, de tabellen, kolommen en db bestaan allemaal. En voor zover ik het kan vinden is INNER JOIN nog steeds toegestaan.

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)
PHP script in nieuw venster Selecteer het PHP script
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
$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()){
    
  }


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
 
PHP hulp

PHP hulp

23/04/2024 14:44:53
 
Frank Nietbelangrijk

Frank Nietbelangrijk

16/02/2015 09:01:45
Quote Anchor link
=> mysqli::prepare returns a statement object or FALSE if an error occurred.
=> 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.
 
J C

J C

16/02/2015 10:04:50
Quote Anchor link
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.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

16/02/2015 10:15:28
Quote Anchor link
Natuurlijk.

Het is eigenlijk een algemeen verhaal. Functies - eigen gemaakte of standaard PHP - kunnen een waarde retouneren:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
function saySomething()
{

    return 'Hello JC';
}


$a = saySomething();

echo $a;
?>


Zo dus ook de bovengenoemde functies.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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!';      
?>


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)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
    //$statement->store_result();
    $result = $statement->store_result();
    if(!$result)
        echo 'mysqli::store_result gaf FALSE terug!';        

    var_dump($result);

    $row_cnt = $statement->num_rows;
    $result = $statement->get_result();    
?>
Gewijzigd op 16/02/2015 10:17:06 door Frank Nietbelangrijk
 
Thomas van den Heuvel

Thomas van den Heuvel

16/02/2015 12:22:52
Quote Anchor link
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?
 
Frank Nietbelangrijk

Frank Nietbelangrijk

16/02/2015 12:37:16
Quote Anchor link
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.
 
Thomas van den Heuvel

Thomas van den Heuvel

16/02/2015 12:42:57
Quote Anchor link
Zucht, ja, dan is mysql injection onmogelijk en je query potentieel nutteloos.

Het gebruik van intval is naïef.
 
J C

J C

16/02/2015 13:03:14
Quote Anchor link
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?


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.
 
Thomas van den Heuvel

Thomas van den Heuvel

16/02/2015 13:21:10
Quote Anchor link
Dat is een manier, maar niet de enige manier.

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.
 
J C

J C

16/02/2015 13:45:38
Quote Anchor link
Zeker waar, ik zat me er al behoorlijk aan te ergeren dat iets wat vernieuwend zou moeten zijn nu zoveel extra werk moet kosten.
 
J C

J C

18/02/2015 19:45:48
Quote Anchor link
kun je een andere manier beschrijven?
Gewijzigd op 18/02/2015 19:46:12 door J C
 
Thomas van den Heuvel

Thomas van den Heuvel

18/02/2015 20:07:45
Quote Anchor link
Ik heb je al een tijdje terug een PM gestuurd, je hebt deze nog niet gelezen.

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)
PHP script in nieuw venster Selecteer het PHP script
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
<?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();
}

?>

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
 
J C

J C

18/02/2015 20:12:43
Quote Anchor link
Ik wist niet eens dat er zoiets bestond als prive berichten.

Ziet er wel goed uit, ik kende de freeresult functie nog niet. Alleen de close functie.
 
Thomas van den Heuvel

Thomas van den Heuvel

18/02/2015 20:23:25
Quote Anchor link
De bovenstaande functies ($db->query, $db->escape, $res->numRows(), $res->fetchAssoc(), $res->freeResult()) zijn geen standaard PHP, die zitten in zelfgeschreven PHP-klasses.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.