0

I want to bind variable number parameters using call_user_func_array in this way(please read comments at the code):


function dbQuery() 
{
    global $dbconnection;
    if (func_num_args() < 1 || func_num_args() === 2) {
       return error('خطای داخلی');
    } else if (func_num_args() === 1) {
       $stmt = $dbconnection->prepare(func_get_arg(0)); // Creating stmt
       if (!$stmt) {
           return error('خطای پایگاه داده');
       }
       if (!$stmt->execute()) {
        return error('خطا در تعامل با پایگاه داده');
       }
       return $stmt;
    } else {
       $args = func_get_args();
       $stmt = $dbconnection->prepare($args[0]); // args[0] is the query with question marks
       if (!$stmt) {
        return error('خطای پایگاه داده');
        }
       array_shift($args);
       foreach ($args as $index => $arg) {
          ${'arg' . $index} = $dbconnection->real_escape_string($arg); // making args as variables because bind_params does not allow direct values
          $args[$index] = ${'arg' . $index};
       }
       if (!call_user_func_array($stmt->bind_param,$args)) { // ERROR IS HERE LINE 67
          return error('خطای امنیتی پایگاه داده');
       }
       if (!$stmt->execute()) {
        return error('خطا در تعامل با پایگاه داده');
       }
       return $stmt;
    }
 }
 $stmt = dbQuery('SELECT * FROM payments WHERE id=?','i',31);
 $result = dbCheck($stmt);
 var_dump($result->fetch_all());

and the error is:

PHP Warning:  Undefined property: mysqli_stmt::$bind_param in /home/mwxgaf/w/projects/foodorder/test.php on line 67
PHP Fatal error:  Uncaught TypeError: call_user_func_array(): Argument #1 ($function) must be a valid callback, no array or string given in /home/mwxgaf/w/projects/foodorder/test.php:67
Stack trace:
#0 /home/mwxgaf/w/projects/foodorder/test.php(76): dbQuery()
#1 {main}
  thrown in /home/mwxgaf/w/projects/foodorder/test.php on line 67

mwxgaf
  • 66
  • 1
  • 9
  • 1
    Can you just use the splat operator? https://stackoverflow.com/a/50682298/231316 – Chris Haas Jul 05 '21 at 14:02
  • 1
    Why are you manually escaping the arguments when using prepared statements? Also, what have you tried to resolve the problem? I would assume that `$stmt->bind_param` is not defined in any way – Nico Haase Jul 05 '21 at 14:03
  • @ChrisHaas I used your solution & it solved another error too ; thanks – mwxgaf Jul 05 '21 at 14:13
  • 1
    `elseif` should be one word in PHP. We shouldn't see any real_escaping with a prepatred statement. Variable variables seem fun when you first learn about them, but eventually you will realize that they prevent you from using powerful array functions on data that is sensibly contained in an array. When you think your code needs varuable variables or `eval()`, you probably need to refactor your code. https://stackoverflow.com/q/13570957/2943403 , https://stackoverflow.com/q/20886289/2943403 , https://stackoverflow.com/q/1913899/2943403 , https://stackoverflow.com/q/45926489/2943403 – mickmackusa Jul 05 '21 at 14:24
  • How about `function dbQuery(string $sql, ...$theRest)`? This way, if `$theRest` is an empty array, you know that you don't need a prepared statement at all. https://stackoverflow.com/a/52323556/2943403 – mickmackusa Jul 05 '21 at 14:43

1 Answers1

3

call_user_func_array expects a callable as the first argument, and $stmt->bind_param is the wrong format for this. [$stmt, 'bind_param'] would be the proper callable


Source: https://www.php.net/manual/en/language.types.callable.php

A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1. Accessing protected and private methods from within a class is allowed.

Nico Haase
  • 11,420
  • 35
  • 43
  • 69