117

Here's my code:

include 'conn.php';
$conn = new Connection();
$query = 'SELECT EmailVerified, Blocked FROM users WHERE Email = ? AND SLA = ? AND `Password` = ?';
$stmt = $conn->mysqli->prepare($query);
$stmt->bind_param('sss', $_POST['EmailID'], $_POST['SLA'], $_POST['Password']);
$stmt->execute();
$result = $stmt->get_result();

I get the error on last line as: Call to undefined method mysqli_stmt::get_result()

Here is the code for conn.php:

define('SERVER', 'localhost');
define('USER', 'root');
define('PASS', 'xxxx');
define('DB', 'xxxx');
class Connection{
    /**
     * @var Resource 
     */
    var $mysqli = null;

    function __construct(){
        try{
            if(!$this->mysqli){
                $this->mysqli = new MySQLi(SERVER, USER, PASS, DB);
                if(!$this->mysqli)
                    throw new Exception('Could not create connection using MySQLi', 'NO_CONNECTION');
            }
        }
        catch(Exception $ex){
            echo "ERROR: ".$e->getMessage();
        }
    }
}

If I write this line:

if(!stmt) echo 'Statement prepared'; else echo 'Statement NOT prepared';

It prints 'Statement NOT prepared'. If I run the query directly in the IDE replacing ? marks with values, it works fine. Please note that $conn object works fine in other queries in the project.

Any help please.......

Kumar Kush
  • 2,347
  • 9
  • 28
  • 39

10 Answers10

150

Please read the user notes for this method:

http://php.net/manual/en/mysqli-stmt.get-result.php

It requires the mysqlnd driver... if it isn't installed on your webspace you will have to work with BIND_RESULT & FETCH!

https://secure.php.net/manual/en/mysqli-stmt.bind-result.php

https://secure.php.net/manual/en/mysqli-stmt.fetch.php

Matt Gibson
  • 13,675
  • 6
  • 45
  • 75
bekay
  • 1,710
  • 1
  • 11
  • 14
  • 4
    Thanks a lot. That worked. I uncommented the **extension=php_mysqli_mysqlnd.dll** in **php.ini**; and restarted Apache2.2 and MySQL services. Should I uncomment the line **extension=php_mysqli_libmysql.dll**? As per another page, mysqlnd is faster than libmysql. Also, can I expect mysqlnd installed on most popular hosting service providers? – Kumar Kush Dec 01 '11 at 17:05
  • I tested the code by removing the line **$stmt = $conn->mysqli->stmt_init();** and the code still worked fine. Is it advisable to do like that? – Kumar Kush Dec 01 '11 at 17:12
  • 1
    **stmt_init()** is only needed for a procedural prepared statement . so you don't need it! Look: [link](http://www.php.net/manual/de/mysqli-stmt.prepare.php) As for the **libmysql**: don't know. And I wouldn't count on hosting providers for the installation of **mysqlnd.dll** ... better try some workaround! – bekay Dec 01 '11 at 17:32
  • 2
    Note: `mysqli_stmt::get_result()` is only available at PHP v5.3.0 or above. – Raptor Nov 28 '12 at 13:54
  • 4
    @bekay You have just saved me a new laptop and a new window. If +10 were available I'd give you it – James Cushing Apr 24 '14 at 10:59
  • 1
    @kush.impetus, Where do you download `php_mysqli_mysqlnd.dll`? I'd only have `php_mysqli.dll` in my `ext` folder. – Pacerier Jun 29 '15 at 10:07
  • @Pacerier: I already had it in my XAMPP installation. I just had to uncomment the relevant line in php.ini. – Kumar Kush Oct 15 '16 at 15:22
51

So if the MySQL Native Driver (mysqlnd) driver is not available, and therefore using bind_result and fetch instead of get_result, the code becomes:

include 'conn.php';
$conn = new Connection();
$query = 'SELECT EmailVerified, Blocked FROM users WHERE Email = ? AND SLA = ? AND `Password` = ?';
$stmt = $conn->mysqli->prepare($query);
$stmt->bind_param('sss', $_POST['EmailID'], $_POST['SLA'], $_POST['Password']);
$stmt->execute();
$stmt->bind_result($EmailVerified, $Blocked);
while ($stmt->fetch())
{
   /* Use $EmailVerified and $Blocked */
}
$stmt->close();
$conn->mysqli->close();
Bert Regelink
  • 2,576
  • 21
  • 17
  • $stmt->bind_result is saved my time. It is a great solution when get_result is not available. – Zafer Feb 11 '15 at 19:38
  • 2
    question: where does the variable $EmailVerfied come from? – Rotimi Feb 27 '17 at 13:19
  • @Akintunde007: `$EmailVerfied` is created by the call to `bind_result()`. – AbraCadaver Jan 24 '18 at 18:54
  • Getting a "Uncaught Error: Call to undefined method mysqli_stmt::bind_results()" error by using the code – Devil's Dream Feb 20 '18 at 08:53
  • If i have sql query like "Select * from table_name" then how to declare inside bind_result(). * operator – Inderjeet Aug 07 '18 at 08:27
  • @Inderjeet If you have fields in table queried like Field_1, Field_2,....Field_n and use * in your query to fetch all of them, you can write your statement as - `$stmt->bind_result($Field_1, $Field_2,......... $Field_n);` – Kumar Kush Oct 31 '18 at 17:44
  • @kush.impetus I know but Is there another way to declare without field name for select * query. – Inderjeet Nov 01 '18 at 04:55
  • This is the solution! I am using hostgator with cpanel in it. And this method solved the problem in my case. – Ozan Atmar Feb 28 '20 at 17:10
46

Your system is missing the mysqlnd driver!

If you are able to install new packages on your (Debian/Ubuntu-based) server, install the driver:

sudo apt-get install php5-mysqlnd

and then restart your web server:

sudo /etc/init.d/apache2 restart
Cody Gray
  • 222,280
  • 47
  • 466
  • 543
M_R_K
  • 4,676
  • 1
  • 34
  • 34
39

for those searching for an alternative to $result = $stmt->get_result() I've made this function which allows you to mimic the $result->fetch_assoc() but using directly the stmt object:

function fetchAssocStatement($stmt)
{
    if($stmt->num_rows>0)
    {
        $result = array();
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$result[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params);
        if($stmt->fetch())
            return $result;
    }

    return null;
}

as you can see it creates an array and fetches it with the row data, since it uses $stmt->fetch() internally, you can call it just as you would call mysqli_result::fetch_assoc (just be sure that the $stmt object is open and result is stored):

//mysqliConnection is your mysqli connection object
if($stmt = $mysqli_connection->prepare($query))
{
    $stmt->execute();
    $stmt->store_result();

    while($assoc_array = fetchAssocStatement($stmt))
    {
        //do your magic
    }

    $stmt->close();
}
Dharman
  • 21,838
  • 18
  • 57
  • 107
MasterKitano
  • 588
  • 4
  • 10
35

With PHP version 7.2 I just used nd_mysqli instead of mysqli and it worked as expected.

Steps to enable it into godaddy hosting server-

  1. Login to cpanel.
  2. Click on "Select PHP version".
  3. As provided the snapshot of the latest configurations uncheck "mysqli" and enable "nd_mysqli".

enter image description here

IRSHAD
  • 2,302
  • 25
  • 35
10

I know this was already answered as to what the actual problem is, however I want to offer a simple workaround.

I wanted to use the get_results() method however I didn't have the driver, and I'm not somewhere I can get that added. So, before I called

$stmt->bind_results($var1,$var2,$var3,$var4...etc);

I created an empty array, and then just bound the results as keys in that array:

$result = array();
$stmt->bind_results($result['var1'],$result['var2'],$result['var3'],$result['var4']...etc);

so that those results could easily be passed into methods or cast to an object for further use.

Hope this helps anyone who's looking to do something similar.

Kirkland
  • 3,207
  • 1
  • 14
  • 17
9

I was getting this same error on my server - PHP 7.0 with the mysqlnd extension already enabled.

Solution was for me (thanks to this page) was to deselect the mysqli extension and select nd_mysqli instead.

NB - You may be able to access the extensions selector in your cPanel. (I access mine via the Select PHP Version option.)

ban-geoengineering
  • 15,533
  • 18
  • 140
  • 225
  • This should be the accepted answer. Much better to enable the extension than editing your entire script to use another method! Oh and it worked for me :) – ArabianMaiden Mar 23 '19 at 10:31
  • I had the same problem. In fact, using PHP's `session_start()` function made me like a non-existent value. Then I upgraded to version `7.2` of PHP and changed the extension of `mysqli` to `nd_mysqli `(fixed). But, I have two questions, what is the difference between the two? and if there would be any gap in security for using that extension? – jecorrales Jul 04 '19 at 17:03
6

Here is my alternative. It is object-oriented and is more like mysql/mysqli things.

class MMySqliStmt{
    private $stmt;
    private $row;

    public function __construct($stmt){
        $this->stmt = $stmt;
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$this->row[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params) or die('Sql Error');
    }

    public function fetch_array(){
        if($this->stmt->fetch()){
            $result = array();
            foreach($this->row as $k => $v){
                $result[$k] = $v;
            }
            return $result;
        }else{
            return false;
        }
    }

    public function free(){
        $this->stmt->close();
    }
}

Usage:

$stmt = $conn->prepare($str);
//...bind_param... and so on
if(!$stmt->execute())die('Mysql Query(Execute) Error : '.$str);
$result = new MMySqliStmt($stmt);
while($row = $result->fetch_array()){
    array_push($arr, $row);
    //for example, use $row['id']
}
$result->free();
//for example, use the $arr
ch271828n
  • 5,683
  • 3
  • 24
  • 44
6

I realize that it's been a while since there has been any new activity on this question. But, as other posters have commented - get_result() is now only available in PHP by installing the MySQL native driver (mysqlnd), and in some cases, it may not be possible or desirable to install mysqlnd. So, I thought it would be helpful to post this answer with info on how get the functionality that get_result() offers - without using get_result().

get_result() is/was often combined with fetch_array() to loop through a result set and store the values from each row of the result set in a numerically-indexed or associative array. For example, the code below uses get_result() with fetch_array() to loop through a result set, storing the values from each row in the numerically-indexed $data[] array:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$result = $stmt->get_result();       
while($data = $result->fetch_array(MYSQLI_NUM)) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

However, if get_result() is not available (because mysqlnd is not installed), then this leads to the problem of how to store the values from each row of a result set in an array, without using get_result(). Or, how to migrate legacy code that uses get_result() to run without it (e.g. using bind_result() instead) - while impacting the rest of the code as little as possible.

It turns out that storing the values from each row in a numerically-indexed array is not so straight-forward using bind_result(). bind_result() expects a list of scalar variables (not an array). So, it takes some doing to make it store the values from each row of the result set in an array.

Of course, the code could easily be modified as follows:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$stmt->bind_result($data[0], $data[1]);
while ($stmt->fetch()) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

But, this requires us to explicitly list $data[0], $data[1], etc. individually in the call to bind_result(), which is not ideal. We want a solution that doesn't require us to have to explicitly list $data[0], $data[1], ... $data[N-1] (where N is the number of fields in the select statement) in the call to bind_results(). If we're migrating a legacy application that has a large number of queries, and each query may contain a different number of fields in the select clause, the migration will be very labor intensive and prone to error if we use a solution like the one above.

Ideally, we want a snippet of 'drop-in replacement' code - to replace just the line containing the get_result() function and the while() loop on the next line. The replacement code should have the same function as the code that it's replacing, without affecting any of the lines before, or any of the lines after - including the lines inside the while() loop. Ideally we want the replacement code to be as compact as possible, and we don't want to have to taylor the replacement code based on the number of fields in the select clause of the query.

Searching on the internet, I found a number of solutions that use bind_param() with call_user_func_array() (for example, Dynamically bind mysqli_stmt parameters and then bind result (PHP)), but most solutions that I found eventually lead to the results being stored in an associative array, not a numerically-indexed array, and many of these solutions were not as compact as I would like and/or were not suited as 'drop-in replacements'. However, from the examples that I found, I was able to cobble together this solution, which fits the bill:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$data=array();
for ($i=0;$i<$mysqli->field_count;$i++) { 
    $var = $i;
    $$var = null; 
    $data[$var] = &$$var; 
}
call_user_func_array(array($stmt,'bind_result'), $data);
while ($stmt->fetch()) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

Of course, the for() loop can be collapsed into one line to make it more compact.

I hope this helps anyone who is looking for a solution using bind_result() to store the values from each row in a numerically-indexed array and/or looking for a way to migrate legacy code using get_result(). Comments welcome.

Community
  • 1
  • 1
mti2935
  • 9,797
  • 3
  • 23
  • 28
3

I have written two simple functions that give the same functionality as $stmt->get_result();, but they don't require the mysqlnd driver.

You simply replace

$result = $stmt->get_result(); with $fields = bindAll($stmt);

and

$row= $stmt->get_result(); with $row = fetchRowAssoc($stmt, $fields);.

(To get the numbers of returned rows you can use $stmt->num_rows.)

You just have to place these two functions I have written somewhere in your PHP Script. (for example right at the bottom)

function bindAll($stmt) {
    $meta = $stmt->result_metadata();
    $fields = array();
    $fieldRefs = array();
    while ($field = $meta->fetch_field())
    {
        $fields[$field->name] = "";
        $fieldRefs[] = &$fields[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $fieldRefs);
    $stmt->store_result();
    //var_dump($fields);
    return $fields;
}

function fetchRowAssoc($stmt, &$fields) {
    if ($stmt->fetch()) {
        return $fields;
    }
    return false;
}

How it works:

My code uses the $stmt->result_metadata(); function to figure out how many and which fields are returned and then automatically binds the fetched results to pre-created references. Works like a charm!

Stefan S.
  • 177
  • 1
  • 8