Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why `mysqli_query()` returns null? How can i figure it out?

Under certain circumstances, the built-in function in PHP called mysqli_query returns null. Such behaviour is not foreseen by the function's documentation that explains how to use it, so I tried to dive in PHP's source code itself, posted on GitHub, to see if I can figure out why sometimes mysqli_query returns null.

The queries themselves doesn't seem to be the problem: I tested the relevant SQL queries in two different ways:

  • Executing them manually in the MySQL Server. They work correctly.
  • Within a script that I created with the single purpose of testing the queries through mysqli_query(). They work under this test, and the function returns true.

However, under certain conditions, those same queries return null. The mysqli link object exists when mysqli_query function starts running, when this "returning null failure" happens.

So, looking in the PHP's GitHub repository, i found the file called mysqli_nonapi.c and, in line 556 within this file, what seems to be the built-in mysqli_query definition. Looking at the code within, it looks like it performs a basic check and, if it fails, it returns null. Here are the first lines linked above:

/* {{{ proto mixed mysqli_query(object link, string query [,int resultmode]) */
PHP_FUNCTION(mysqli_query){ 
    MY_MYSQL           *mysql;
    zval               *mysql_link;
    MYSQLI_RESOURCE    *mysqli_resource;
    MYSQL_RES          *result = NULL;
    char               *query = NULL;
    size_t              query_len;
    zend_long           resultmode = MYSQLI_STORE_RESULT;
    if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
        return;
    }
    // [...]
}

Even though I have used sometimes C code, I just know a little about C. I am aware that it uses pointers and I guess those parameters which name start with * are pointers. Anyways, I am not sure on how to interpretate this piece of code, or figuring out how it's internal flow affects PHP execution.

Long story short: I can assume somehow, the initial check shown above within the function failed for some reason. But, to find out why, I need to understand that piece of code first.

I am afraid I cannot isolate the issue to trigger the error outside production environment, which would be very useful for exhaustive testing. So, what options do I have left? Is there something I can do to debug that internal piece of code, or otherwise, figuring out why it might be failing within?

I made the tests in both PHP5 and PHP7; it fails the same way in both of them.

like image 770
SebasSBM Avatar asked May 15 '18 09:05

SebasSBM


Video Answer


1 Answers

This is called undefined behaviour in PHP. Most instances of it have been eradicated in PHP 8, but prior to that version when you passed a wrong parameter to a built-in function, that function would usually throw a warning and return null (or false).

There were a lot of circumstances when no warning was produced at all! This behaviour was not documented on each page as this would be a mess and by definition "undefined behaviour" has no defined behaviour.

This means that code like the following would throw no warning and simply return null:

//                                          V - string passed instead of a numerical value
var_dump(mysqli_query($mysqli, 'SELECT 1', 'foo'));

PHP was very forgiving with parameter types and when you passed the wrong type, it tried to convert it into the proper type, but when this was not possible then PHP had no defined behaviour of what should happen. Thankfully, this has been fixed in 99% of cases in PHP 8.0.

like image 126
Dharman Avatar answered Sep 24 '22 01:09

Dharman