0

I am trying to upgrade an old application to PHP 7.2. It contains an sql class PHP file with the following function which I have modified to use mysqli:

    function query($query, $index=0)
    {
        // query
        if (!$this->res[$index] = mysqli_query($this->connection, $query))
        {
            // if query fails show error
            $this->error('<strong>invalid query</strong>:<br />' . $query . '<br />');
            return false;
        }

        // statistical information
        $this->num_rows[$index] = @mysqli_num_rows($this->res[$index]);
        $this->num_flds[$index] = @mysqli_num_fields($this->res[$index]);
        $this->num_aff[$index]  = @mysqli_affected_rows($this->connection);
        $this->last_id             = @mysqli_insert_id($this->connection);

        return true;
    }

This function throws the folling error:

E_WARNING Error in file �sql.class.php� at line 132: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given E_WARNING Error in file �sql.class.php� at line 133: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given

My initial thought was that the query was failing. However, including this line inside the function...

print_r(mysqli_fetch_assoc($this->res[$index]));

results in the following output:

Array ( [s_id] => 2088b4cc0d026c2742e8e0cb7d7c8e95 )

In the output above, the query is returning a session ID. That leaves me a bit confused because the value of $this->res[$index] is not a boolean, yet the Warning says it is.

Edit:

If I include this in the function:

        echo mysqli_num_rows($this->res[$index]);
        echo mysqli_num_fields($this->res[$index]);

Each line echos the correct value of 1 but each line also produces the boolean Warning...

E_WARNING Error in file �sql.class.php� at line 125: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given
E_WARNING Error in file �sql.class.php� at line 126: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given
hubalazs
  • 448
  • 4
  • 13
Joshua
  • 187
  • 12
  • 1
    The rule #1: **trust your eyes**. If mysqli says it's a boolean **it is so**. Despite what you think. Most likely it got messed up due to bizarre $index stuff. Or s some other mistake of the kind. [Configure your mysqli to throw exceptions](https://phpdelusions.net/mysqli/error_reporting) and use the **stack trace** to track down the actual problem query. – Your Common Sense Aug 14 '19 at 06:11
  • Thanks for your suggestion @YourCommonSense but no additional exceptions are thrown when using `mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);`. It does show a particular message if I intentionally break the query, but not as it is currently written. – Joshua Aug 14 '19 at 06:33
  • 1
    What is also strange, you have a @ in front of the function call so the error must be suppressed. Are you sure you are running this file you posted here? – Your Common Sense Aug 14 '19 at 08:35
  • Yes same file. I think @Anton is on the right track as were you with this comment `Most likely it got messed up due to bizarre $index stuff.`. – Joshua Aug 14 '19 at 20:14
  • See also [How to change mysql to mysqli?](https://stackoverflow.com/a/56997881/1839439) It looks like you are completely missing the point of upgrading to MySQLi. – Dharman Aug 16 '19 at 19:04

1 Answers1

0

mysqli_query return values : If can be mysqli_result object,true, false

Returns FALSE on failure. For successful SELECT, SHOW, DESCRIBE or EXPLAIN queries mysqli_query() will return a mysqli_result object. For other successful queries mysqli_query() will return TRUE.

try this modification to see which query really successful but result was true

function query($query, $index=0)
{
    $this->res[$index] = mysqli_query($this->connection, $query);
    // query
    if (is_bool($this->res[$index])) {
        if ($this->res[$index] === false)
        {
            // if query fails show error
            $this->error('<strong>invalid query</strong>:<br />' . $query . '<br />');
            return false;
        } else {
            // query was successful, but the result is not a mysqli_result object
            $this->warning('<strong>success with no returned data query</strong>:<br />' . $query . '<br />');
            return true;
        }
    }


    // statistical information
    $this->num_rows[$index] = @mysqli_num_rows($this->res[$index]);
    $this->num_flds[$index] = @mysqli_num_fields($this->res[$index]);
    $this->num_aff[$index]  = @mysqli_affected_rows($this->connection);
    $this->last_id             = @mysqli_insert_id($this->connection);

    return true;
}

Check that $this->warning is exist in your code, or update it to what it will be proper

Anton
  • 417
  • 3
  • 9
  • Thanks @Anton. That produces the following: `success with no returned data query: UPDATE sessions SET s_lastact='1565811945' WHERE s_id='66747aaaca703082d8c57e0d8bb48b2b' ` Also, there are no warnings about booleans supplied to mysqli_ functions. Could that be simply because you moved `$this->res[$index] = mysqli_query($this->connection, $query);` out of the `if` condition? If so why did this work before without the change using `mysql_*` functions? Reading the manual it looks like the return behavior of `mysql_query` is the same as `mysqli_query`. PS: used `echo` instead of `$this->warning` – Joshua Aug 14 '19 at 20:10
  • Oof, spoke too soon. still have the Warnings. – Joshua Aug 14 '19 at 21:36
  • i think you may missed the point in the notes about the result of the function. It will **only** have the **mysqli_result object** as a result if your query is **SELECT** (we can ignore SHOW, DESCRIBE and EXPLAINE for now). And in you comment I see that the query was **UPDATE**, so based on the docs, the reqult of the query will be a **boolean** and not a **mysqli_result object**. That is why your **mysqli_num_rows** throws the warning, because it got not the object but a boolean – Anton Aug 15 '19 at 03:47
  • @disconnected you can modify the code and wrap `$this->num_rows[$index] = @mysqli_num_rows($this->res[$index]);` into if statement . Or like this: `$this->num_rows[$index] = is_bool($this->res[$index]) ? 0 : @mysqli_num_rows($this->res[$index]);` .So when your query is not a **SELECT** query, then your $this->num_rows[$index] will be equals to 0, what is logically correct, because you didn't fetched any rows: you may have affected some rows (retrieving which you have a statement later in the code), but didn't fetch any – Anton Aug 15 '19 at 03:59
  • Awesome and thanks for the help @Anton. Understood now. I up-voted your answer but someone else down-voted it :( – Joshua Aug 15 '19 at 09:13