0

I am refractoring some of my old code and I am creating a database class with a INSERT function. For purposes of testing I have left it outside of the class and want to make it handle errors.

I want to remove the php errors and return my own errors. Currently I have the below and works fine with an insert on duplicate key but when I test removing the type argument from the bind_param I get the following error:

Warning: mysqli_stmt::bind_param(): Invalid type or no types specified in /home/matt500b/csgoberry/public/catch.php on line 17

Executing the statement failed: No data supplied for parameters in prepared statement

How can I remove the Warning issue and keep just my returned string? Or for production servers what is the best method for this type of action.

Also what other errors can I simulate with regards to mysqli queries?

function INSERT($link, $sql, $args=null) {
    
    if ($stmt = $link->prepare($sql)) {
        for($i=0; $i<count($args); $i++) {
            $stmt->bind_param($args[$i]["type"], $args[$i]["value"]); 
        }
        if(!$stmt->execute()) {
            return 'Executing the statement failed: ' . htmlspecialchars($stmt->error);
            exit();
        }
    }
    else {
        return 'Preparing the statement failed: ' . htmlspecialchars($link->error);
        exit();
    }
    
    return 'Finished';
}

$query = "INSERT INTO insertTest (`value`) VALUES (?)";
$queryArgs[] = array("type"=>"", "value"=>"test1");
echo INSERT($link, $query, $queryArgs);
Community
  • 1
  • 1
Matt
  • 1,749
  • 2
  • 12
  • 26
  • `try catch`? http://stackoverflow.com/questions/17549584/how-to-efficiently-use-try-catch-blocks-in-php – random_user_name May 12 '16 at 21:45
  • I am simulating errors to get all errors caught and displayed properly. I have intentionally left `"type"=>""` empty. Thus voting not duplicate as the issue regarding how to handle such errors – Matt May 12 '16 at 21:46
  • tried try/catch around the execute however my custom error doesn't show and only the php Warning error shows – Matt May 12 '16 at 21:53
  • Try/catch is for exceptions not php warnings or errors. Don't think you can achieve this with MySqli class but you can certainly do it with PDO class. – TheDrot May 12 '16 at 21:55
  • Production servers usually have error reporting off, so you wouldn't see the warnings there. If you're ok with that. – TheDrot May 12 '16 at 22:02
  • See http://stackoverflow.com/questions/1241728/can-i-try-catch-a-warning for how to use `set_error_handler()` to intercept warnings and PHP errors that don't throw. – Barmar May 12 '16 at 22:10
  • You see how you checked the return values of both `prepare()` and `execute()`? Do that for `bind_param()` as well. – Sammitch May 12 '16 at 22:18
  • I am closing this question for sake of future visitors, who will be looking for a correct way of error handling, not a question asking to fix someone's particular code. – Your Common Sense May 13 '16 at 07:29
  • However, if you got any questions after reading my answer, you're welcome to ask. – Your Common Sense May 13 '16 at 07:30

2 Answers2

2

To be frank, the whole idea of the error handling is wrong. A function that returns an error message is a deadly sin. A function should return something related to its purpose. For example, an insert function should return a statement, to let you use, for example, affected_rows variable from it.

While errors have to be handled entirely different way.

Besides, the way you are using mysqli is wrong, and this code will never work anyway.

Assuming you are refactoring for a reason, and can use an already slightly outdated PHP version of 5.6, here is the function to run ANY query, not only INSERT:

function query($link, $query, $params = NULL, $types = NULL)
{
    if (!$params)
    {
        return $link->query($query);
    }
    $statement = $link->prepare($select);
    $types = $types ?: str_repeat('s', count($params));
    $statement->bind_param($types, ...$params);
    $statement->execute();
    return $statement;
}

And this is how it can be used

$query = "INSERT INTO insertTest (`value`) VALUES (?)";
query($link, $query, ['test1']);

or, in case you want to set types,

$query = "INSERT INTO insertTest (`value`) VALUES (?)";
query($link, $query, ['test1'], "s");

Now, to the exciting topic of error reporting. Just do it as it explained in this answer.

In short: mysqli can report its errors already, and can do it way better than your code. So just leave it alone and let PHP handle all errors.

Community
  • 1
  • 1
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
0

If you want to inhibit the warnings, you can place the @ operator in front of the function or method call causing the warning:

@$stmt->bind_param($args[$i]["type"], $args[$i]["value"]);

Typically though, you should be checking for invalid data passed into your function before passing that data to a lower-level function, meaning @ is not required as the lower-level function would not be called in an error situation.

Keiji
  • 880
  • 5
  • 12
  • No need to test the input data manually, because mysqli have ALL the checking routines already, much more you can ever devise. So one should actually just let mysqli to check and to tell you what was the error. Besides, @ is evil. No excuses. – Your Common Sense May 13 '16 at 07:32
  • Yes, @ is evil. I was answering the question (OP wanted to inhibit warnings) and explaining that doing your own error checking is better than using @. – Keiji May 13 '16 at 09:46