PHP & MySQL: zerofill is lost when using mysqli->p

2019-08-24 10:39发布

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.

Any hint of how to solve this problem is welcome.

3条回答
Summer. ? 凉城
2楼-- · 2019-08-24 11:15

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

查看更多
太酷不给撩
3楼-- · 2019-08-24 11:29

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.

查看更多
萌系小妹纸
4楼-- · 2019-08-24 11:31

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.

查看更多
登录 后发表回答