skip to Main Content

I have been trying to solve this problem for a while now. I am getting an unexpected error namely “mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in”

Below is the sample code referring to where this error is happening.

function tep_db_input($string, $link = 'db_link') {
    global $$link;

    return mysqli_real_escape_string($$link, $string);
}

The mysqli object is being made in this piece of code.

function tep_db_connect($server = DB_SERVER, $username = DB_SERVER_USERNAME, $password = DB_SERVER_PASSWORD, $database = DB_DATABASE, $link = 'db_link') {
    global $$link;

    if (USE_PCONNECT == 'true') {
      $server = 'p:' . $server;
    }

    $$link = mysqli_connect($server, $username, $password, $database);

    if ( !mysqli_connect_errno() ) {
      mysqli_set_charset($$link, 'utf8');
    } 

    return $$link;
}

The rest of the mysqli functions like this are all in the same file. This file gets included at the start of the page. Like this.

// make a connection to the database... now
tep_db_connect() or die('Unable to connect to database server!');

A little bit of background to this whole situation. It’s an OsCommerce webshop a really old version at that, recently we have decided to migrate from PHP 5.3 to 5.6 forcing us to use the new mysqli_* extension instead of mysql_*.
Ever since I have been getting multiple errors pertaining to the issue where the object won’t work within another function, while I’m still using global to get it wihin the scope. I’ve done a var_dump right before the mysqli_real_escape_string() is being called and get a proper mysqli object back.

Currently this version of the website is not live so I’m accessing it via editing the hosts file. I’m not sure if this is influencing any behaviour but I thought any info added to the story could help.

function tep_db_input($string, $link = 'db_link') {
    global $$link;
    var_dump($$link);

    return mysqli_real_escape_string($$link, $string);
}

Results

object(mysqli)#1 (19) { ["affected_rows"]=> int(161) ["client_info"]=> string(79) "mysqlnd 5.0.11-dev - 20120503 - $Id: 3c688b6bbc30d36af3ac34fdd4b7b5b787fe5555 $" ["client_version"]=> int(50011) ["connect_errno"]=> int(0) ["connect_error"]=> NULL ["errno"]=> int(0) ["error"]=> string(0) "" ["error_list"]=> array(0) { } ["field_count"]=> int(2) ["host_info"]=> string(25) "Localhost via UNIX socket" ["info"]=> NULL ["insert_id"]=> int(0) ["server_info"]=> string(14) "5.5.41-MariaDB" ["server_version"]=> int(50541) ["stat"]=> string(149) "Uptime: 2338516 Threads: 8 Questions: 166189149 Slow queries: 0 Opens: 1664692 Flush tables: 2 Open tables: 400 Queries per second avg: 71.066" ["sqlstate"]=> string(5) "00000" ["protocol_version"]=> int(10) ["thread_id"]=> int(2568661) ["warning_count"]=> int(0) }

Yet I’m still getting the error saying there is null given in the function which makes no sense to me since there clearly is something in the variable as the var_dump shows.

I’m well aware that using global in combination with mysqli isn’t the best practice so please do not try to correct me on that. I’m simply looking for the cause why my object dissapears right before the function is called.

My question here is why is the object not being recognized by the function yet the var_dump shows it’s a mysqli object.

Many thanks for taking the time to read through all of this and I hope anyone can be of help.

EDIT1:
Just to double check the answer given by @xXDarioXx
I did two var_dumps of the variable but in different forms. Here is the code.

echo $string;
echo '<br/>';
var_dump($db_link);
echo '<br/>';
echo '<br/>';
var_dump($$link);
echo '<br/>';
echo '<br/>';

This returned the same mysqli object but slightly different. Here is the output.

u2l14a8l846b5le667ibnio0p5

$db_link object

object(mysqli)#1 (19) { ["affected_rows"]=> int(161) ["client_info"]=> string(79) "mysqlnd 5.0.11-dev - 20120503 - $Id: 3c688b6bbc30d36af3ac34fdd4b7b5b787fe5555 $" ["client_version"]=> int(50011) ["connect_errno"]=> int(0) ["connect_error"]=> NULL ["errno"]=> int(0) ["error"]=> string(0) "" ["error_list"]=> array(0) { } ["field_count"]=> int(2) ["host_info"]=> string(25) "Localhost via UNIX socket" ["info"]=> NULL ["insert_id"]=> int(0) ["server_info"]=> string(14) "5.5.41-MariaDB" ["server_version"]=> int(50541) ["stat"]=> string(149) "Uptime: 2341490 Threads: 2 Questions: 166712462 Slow queries: 0 Opens: 1668302 Flush tables: 2 Open tables: 400 Queries per second avg: 71.199" ["sqlstate"]=> string(5) "00000" ["protocol_version"]=> int(10) ["thread_id"]=> int(2583258) ["warning_count"]=> int(0) } 

$$link object.

object(mysqli)#1 (19) { ["affected_rows"]=> int(-1) ["client_info"]=> string(79) "mysqlnd 5.0.11-dev - 20120503 - $Id: 3c688b6bbc30d36af3ac34fdd4b7b5b787fe5555 $" ["client_version"]=> int(50011) ["connect_errno"]=> int(0) ["connect_error"]=> NULL ["errno"]=> int(0) ["error"]=> string(0) "" ["error_list"]=> array(0) { } ["field_count"]=> int(2) ["host_info"]=> string(25) "Localhost via UNIX socket" ["info"]=> NULL ["insert_id"]=> int(0) ["server_info"]=> string(14) "5.5.41-MariaDB" ["server_version"]=> int(50541) ["stat"]=> string(149) "Uptime: 2341490 Threads: 2 Questions: 166712462 Slow queries: 0 Opens: 1668302 Flush tables: 2 Open tables: 400 Queries per second avg: 71.199" ["sqlstate"]=> string(5) "00000" ["protocol_version"]=> int(10) ["thread_id"]=> int(2583258) ["warning_count"]=> int(0) } 

I have tried switching the variables around to see if it truly was an issue with the dynamic variable but it seems the latter variable always outputs an object with affected rows -1 this might be another piece of info why the object dissapears of becomes unusable.

EDIT2:
Log with the errors being thrown by PHP

[01-Sep-2016 17:38:21 Europe/Amsterdam] PHP Warning:  mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in /home/user/domains/domain/public_html/includes/functions/database.php on line 160
[01-Sep-2016 17:38:21 Europe/Amsterdam] PHP Warning:  mysqli_query() expects parameter 1 to be mysqli, null given in /home/user/domains/domain/public_html/includes/functions/database.php on line 53
[01-Sep-2016 17:38:21 Europe/Amsterdam] PHP Warning:  mysqli_errno() expects parameter 1 to be mysqli, null given in /home/user/domains/domain/public_html/includes/functions/database.php on line 53
[01-Sep-2016 17:38:21 Europe/Amsterdam] PHP Warning:  mysqli_error() expects parameter 1 to be mysqli, null given in /home/user/domains/domain/public_html/includes/functions/database.php on line 53

Errors are being thrown here because of a tep_db_query using tep_db_input to escape a key in the query. Hence the mysqli_real_escape_string that is being thrown first and then the others because the tep_db_input fails since the object ‘dissapears’.

I have done a small test to see where exactly the object starts behaving weirdly. I modified the tep_db_input function to pass along numbers for debugging.

 function tep_db_input($string, $num = 0, $link = 'db_link') {
   global $$link;

   echo '<br/>';
   echo '<br/>';
   echo $num;
   echo '<br/>';

   echo $string;
   echo '<br/>';
   var_dump($db_link);
   echo '<br/>';
   echo '<br/>';
   var_dump($$link);
   echo '<br/>';
   echo '<br/>';

   return mysqli_real_escape_string($$link, $string);
}

This gave me the following results.

1
u2l14a8l846b5le667ibnio0p5

“Object 1 from previous test”

“Object 2 from previous test”

2
u2l14a8l846b5le667ibnio0p5
NULL <- This is where object 1 should be dumped

NULL <- This is where object 2 should be dumped

The code where this is being executed is as follows.

function _sess_read($key) {
    $value_query = tep_db_query("select value from " . TABLE_SESSIONS . " where sesskey = '" . tep_db_input($key, 1) . "' and expiry > '" . time() . "'");
    $value = tep_db_fetch_array($value_query);

    if (isset($value['value'])) {
        return $value['value'];
    }

    return '';
}

function _sess_write($key, $val) {
    global $SESS_LIFE;

    $expiry = time() + $SESS_LIFE;
    $value = $val;
    $check_query = tep_db_query("select count(*) as total from " . TABLE_SESSIONS . " where sesskey = '" . tep_db_input($key , 2) . "'");
    $check = tep_db_fetch_array($check_query);

    if ($check['total'] > 0) {
        return tep_db_query("update " . TABLE_SESSIONS . " set expiry = '" . tep_db_input($expiry) . "', value = '" . tep_db_input($value) . "' where sesskey = '" . tep_db_input($key) . "'");
    } else {
        return tep_db_query("insert into " . TABLE_SESSIONS . " values ('" . tep_db_input($key) . "', '" . tep_db_input($expiry) . "', '" . tep_db_input($value) . "')");
    }
}

These two are called in

session_set_save_handler('_sess_open', '_sess_close', '_sess_read', '_sess_write', '_sess_destroy', '_sess_gc');

3

Answers


  1. You are using dynamic variable name

    $$link is a variable of name db_link by default in tep_db_connect

    $db_link does not exist so it returns null

    Login or Signup to reply.
  2. Custom session save handlers are odd beasts. They have one foot in user land, where things behave as you would expect, and another foot in the ethereal world of the engine where dark magic resides. To wit:

    [T]he write and close handlers are called after object destruction and therefore cannot use objects…

    It’s unclear to me exactly which session function is failing, but I suspect it is _sess_write. If you wire in a debug_print_backtrace at the top of tep_db_connect that will clarify.

    Nevertheless, what I’d suggest doing is to put all your session functions in a class, then in that class’ open method to get a link to your ADOdb and store it as a member variable, then register your session functions on an instance of that class. This will keep the link in the object and protected from the normal destruction of other global objects.

    class CustomSaveHandler extends SessionHandlerInterface {
        public function open($path, $name) {
            this->db = tep_db_connect(...);
        }
    
        public function read($id) {
            // MySQL database calls using $this->db; you'll have to refactor how
            // you're calling your tep_ functions
        }
    
        // etc.
    }
    session_set_save_handler(new CustomSaveHandler);
    

    For reference, a similar problem with custom session handlers and ADOdb.

    Login or Signup to reply.
  3. Try this

      function tep_db_connect($server = DB_SERVER, $username = DB_SERVER_USERNAME, $password = DB_SERVER_PASSWORD, $database = DB_DATABASE, $link = 'db_link') {
        global ${$link};
    
        if (USE_PCONNECT == 'true') {
          $server = 'p:' . $server;
        }
    
        ${$link} = mysqli_connect($server, $username, $password, $database);
    
        if ( !mysqli_connect_errno() ) {
          mysqli_set_charset(${$link}, 'utf8');
        }
    
        return ${$link};
      }
    
    
    
      function tep_db_input($string, $link = 'db_link') {
        global ${$link};
    
        return mysqli_real_escape_string(${$link}, $string);
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search