开发者

Zerofill is lost when using mysqli->prepare()

Using: MySQL 5.1 + PHP 5.3.5

MySQL:

id in "table" is defined as: mediumint(6) zerofill not null

I get the expected result when using:

$mysqli->query("SELECT id FROM table WHERE id = 1");
while($row = $ret->fetch_array(MYSQLI_ASSOC)) $arr[] = $row;
>>> $arr[0]["id"] = 000001

But not when I use prepared statement:

$ret = $mysqli->prepare("SELECT id FROM table WHERE id = ?");
call_user_func_array(array($ret,"bind_param"),array("i",1));
$ret->execute();
$ret->store_result();
$meta = $ret->result_metadata();
$fields = $meta->fetch_fields();
$cols = array(); $data = array();
foreach($fields as $field) $cols[] = &$data[$field->name];
call_user_func_array(array($ret, 'bind_result'), $cols);
while($ret->fetch()) {
    $row = array();
    foreach($data开发者_开发技巧 as $key => $val) $row[$key] = $val;
    $arr[] = $row;
}
>>> $arr[0]["id"] = 1

When trying the prepared statement directly in the MySQL console, it shows as expected (it is not MySQL).

According to PHP mysqli_stmt::bind_result documentation I found this:

Depending on column types bound variables can silently change to the corresponding PHP type.

I need to show the number with the trailing zeros WITHOUT having to do it in a later step. There are so many fields with zerofill and the process is practically automated from the data to the screen, so trying to fix this after this code, will require mayor changes.


The zerofill gets lost, because mysqli knows that the column is of type integer and so the type of the php variable becomes also int and so the leading zeros get lost.

This seems only to happen when you use prepared statements with mysqli (PDO seems not to have this behavior).

To prevent mysqli the type of the variable to integer you have to change the type in MySQL to something that is returned as a string.

There are two ways:

  1. CAST(intCol AS CHAR) casts the integer including the leading zeros to a string.
  2. Using the zerofilled integer in a string context, e.g. CONCAT(intCol, "").

Notice: If you use this value in an HTML5 input field of type number, this will also strip off leading zeros (at least in some browsers). To solve this problem have a look at this answer.


Temporally, I solved it adding these lines:

define("ZEROFILL_FLAG",64);
$zeros = array();
foreach($fields as $field) {
    $zeros[$field->name] = $field->flags & ZEROFILL_FLAG ? $field->length : 0;
    $cols[] = &$data[$field->name];
}   
call_user_func_array(array($ret, 'bind_result'), $cols);
while($ret->fetch()) {
    $row = array();
    foreach($data as $key => $val) {
        $row[$key] = $zeros[$key] > 0 ? sprintf('%0'.$zeros[$key].'s', $val) : $val;
    }   
    $arr[] = $row;
}  

Still I hope someone can show me a better way to solve it.


Another solution was to specify the field as decimal(6,0). For some reason it works as expected (no changes to the code required).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜