4

我有一个包含一列bit(1)和以下查询的表:SELECT my_bit FROM my_table.

当我echophp页面上显示结果时,该值显示为string(3) %qu 列上的位值是 0 还是 1。这怎么可能?

以下查询解决了echoing在网页上时的问题:SELECT CAST(my_bit AS UNSIGNED) AS my_bit FROM my_table.

但是,上述两个查询都在命令行工具上工作。那里没有string(3)

选择数据时一切正常,之间没有区别

  1. SELECT * FROM my_table WHERE my_bit=0
  2. SELECT * FROM my_table WHERE my_bit=(0)

使用命令行工具或 Web 界面php页面时。(此处建议使用后者。)Echoing必须使用CAST函数完成,但WHERE不受括号影响:返回正确的行。

主要问题

  1. 为什么返回的bit类型值无论是 0 还是 1都echoed一样?stringbit
  2. bit(1)使用类型列插入/选择数据时,是否有任何特殊问题需要考虑?(快速测试表明一切都按预期工作:0 插入为 0,1 插入为 1,但我可能遗漏了一些东西。)

我正在使用 MAMP 进行本地测试:PHP 5.3.2 和 MySQL 5.1.44。命令行工具指的是 Sequel Pro(不是 MAMP 的 PhpAdmin)。Php页面utf-8和查询使用SET NAMES 'utf8'.


更新:代码

CREATE TABLE `my_table` (
  `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `my_bit` bit(1) NOT NULL,
  PRIMARY KEY (`id`,`lto_muu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

INSERT INTO `my_table` (`id`, `my_bit`) VALUES (null, 0), (null,1)

//php page
//query option 1
SELECT `id`, `my_bit`  FROM `my_table`
//query option 2
SELECT `id`, CAST(`my_bit` AS UNSIGNED) AS `my_bit`  FROM `my_table`

$mysqli = new mysqli("localhost", "root", "root","my_db");
$q = "SELECT `id`, `my_bit`  FROM `my_table`";//returns 2 rows

$r = $mysqli->query($q);

while($row = mysqli_fetch_array($r,MYSQLI_ASSOC)){
echo 'id: ' . $row['id'] . ' - bit: ' . $row['my_bit'] . '<br />';
}

查询选项 1 打印出:

id: 1 - bit: %qu
id: 2 - bit: %qu

查询选项 2 打印出:

id: 1 - bit: 0
id: 2 - bit: 1

更新 2:Álvaro 的代码

$conn = new mysqli('localhost', 'root', 'root','test');
//$mysqli->set_charset('utf8');
$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

//opt 1
$q = 'SELECT cast(my_bit as unsigned) as my_bit, my_multiple_bit FROM bit_test';
//opt2 
//$q = 'SELECT my_bit, my_multiple_bit FROM bit_test';
$r = $conn->query($q);
while($row = mysqli_fetch_array($r, MYSQLI_ASSOC)){
    echo bin2hex($row['my_bit']) . '<br />';
    echo bin2hex($row['my_multiple_bit']) . '<br />';
    var_dump($row);
    echo '<br /><br />';
}

使用PHP 5.2.12 选项1 和 2 都打印:

30
07
array(2) {
  ["my_bit"]=>
  string(1) "0"
  ["my_multiple_bit"]=>
  string(1) ""
}
31
80
array(2) {
  ["my_bit"]=>
  string(1) "1"
  ["my_multiple_bit"]=>
  string(1) "�"
}

使用PHP 5.3.2 opt 1 打印:

30
257175
array(2) {
  ["my_bit"]=>
  string(1) "0"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}
31
257175
array(2) {
  ["my_bit"]=>
  string(1) "1"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}

并选择 2:

257175
257175
array(2) {
  ["my_bit"]=>
  string(3) "%qu"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}
257175
257175
array(2) {
  ["my_bit"]=>
  string(3) "%qu"
  ["my_multiple_bit"]=>
  string(3) "%qu"
}

PHP 5.3.2 允许打印%qu。这有道理吗?

4

2 回答 2

8

简短的回答

好的,这是我自己问题的简短答案。如果您想确保bit(1)以整数形式检索该列,请在检索bit(1)值时使用以下查询:

$q = 'SELECT (my_bit + 0) AS my_bit, (my_multiple_bit + 0) AS my_multiple_bit FROM bit_test';

如果不使用“+ 0”,则将bit(1)列的值视为binary string这是我对自己说“RTM”的那一刻......

通过谷歌的魔力在这里找到了类似的东西......

如果您对快速解决方案感到满意,请立即停止阅读。

现在是凌乱/冗长的答案(让我们使用 Álvaro 的代码)

让我们创建表并使用四个不同的查询以及我的 MAMP 安装中可用的两个 PHP 版本:5.3.2 和 5.2.12。

$conn = new mysqli('localhost', 'root', 'root','my_db');

$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');

$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

//q1
$q = 'SELECT (my_bit + 0) AS my_bit, (my_multiple_bit + 0) AS my_multiple_bit FROM bit_test';
//q2
//$q = 'SELECT cast(my_bit as unsigned) as my_bit, my_multiple_bit FROM bit_test';
//q3
//$q = 'SELECT HEX(my_bit) AS my_bit , HEX(my_multiple_bit) AS my_multiple_bit FROM bit_test';
//q4
//$q = 'SELECT my_bit, my_multiple_bit FROM bit_test';

$r = $conn->query($q);

//let's echo a few options
//plain gives unaltered result
//bin2hex gives hexadecimal number of an ASCII string (since) the values are treated as strings
//base16to10 gives decimal representation of hexadecimal value
//yes, the two functions are contradictionary (dependable of the query in use)
//but I'll echo their result anyway
while($row = mysqli_fetch_array($r, MYSQLI_ASSOC)){
  echo 'plain: ' . $row['my_bit'] . '<br />';
  echo 'plain: ' . $row['my_multiple_bit'] . '<br />';
  echo 'bin2hex: ' . bin2hex($row['my_bit']) . '<br />';
  echo 'bin2hex: ' . bin2hex($row['my_multiple_bit']) . '<br />';
  echo 'base16to10: ' . base_convert($row['my_bit'],16,10) . '<br />';
  echo 'base16to10: ' . base_convert($row['my_multiple_bit'],16,10) . '<br />';
  var_dump($row);
  echo '<br /><br />';
}

以下是不同查询的结果

我真正感兴趣的是普通输出 and var_dump,但是您也可以检查bin2hexandbase16to10输出在查找数字是否与其对应值有一些链接时会很有用:数字 0、7、1 和 128(存储的值表的四bit列)。

q1——安全的赌注——输出在 PHP 5.3.2 和 5.2.12 中是相同的

plain: 0
plain: 7
bin2hex: 30
bin2hex: 37
base16to10: 0
base16to10: 7
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(1) "7" }

plain: 1
plain: 128
bin2hex: 31
bin2hex: 313238
base16to10: 1
base16to10: 296
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(3) "128" }

q2 – 输出的一些差异

可以正常工作,bit(1)但输出有些问题my_multiple_bit

PHP 5.2.12:
plain: 0
plain: 
bin2hex: 30
bin2hex: 07
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(1) "" }

plain: 1
plain: �
bin2hex: 31
bin2hex: 80
base16to10: 1
base16to10: 0
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(1) "�&quot; } 
PHP 5.3.2
plain: 0
plain: %qu
bin2hex: 30
bin2hex: 257175
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(3) "%qu" }

plain: 1
plain: %qu
bin2hex: 31
bin2hex: 257175
base16to10: 1
base16to10: 0
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(3) "%qu" }

q3 – PHP 5.3.2 和 5.2.12 中的输出相同

这也是一个可以安全使用的查询。只需记住将检索到的十六进制数转换为十进制数。

plain: 0
plain: 7
bin2hex: 30
bin2hex: 37
base16to10: 0
base16to10: 7
array(2) { ["my_bit"]=> string(1) "0" ["my_multiple_bit"]=> string(1) "7" }

plain: 1
plain: 80
bin2hex: 31
bin2hex: 3830
base16to10: 1
base16to10: 128
array(2) { ["my_bit"]=> string(1) "1" ["my_multiple_bit"]=> string(2) "80" }

q4 – 输出很奇怪

PHP 5.2.12 可以正常工作,bit(1)但如果对正在使用的 PHP 版本或其行为有任何疑问,我不会使用此查询。

PHP 5.2.12
plain:
plain: 
bin2hex: 00
bin2hex: 07
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "" ["my_multiple_bit"]=> string(1) "" }

plain: 
plain: �
bin2hex: 01
bin2hex: 80
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(1) "" ["my_multiple_bit"]=> string(1) "�&quot; } 
PHP 5.3.2
plain: %qu
plain: %qu
bin2hex: 257175
bin2hex: 257175
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(3) "%qu" ["my_multiple_bit"]=> string(3) "%qu" }

plain: %qu
plain: %qu
bin2hex: 257175
bin2hex: 257175
base16to10: 0
base16to10: 0
array(2) { ["my_bit"]=> string(3) "%qu" ["my_multiple_bit"]=> string(3) "%qu" } 

最后的想法和自我说明

RTM,测试再测试。

也很高兴知道这个%qu输出是否是 PHP 5.3.2 独有的错误。(或者还有哪些其他 PHP 版本受到影响。)

因此,Álvaro 的答案在使用CASTHEX从 DB 检索值的意义上是正确的。该手册揭示了额外的“+0”方法,这似乎消除了不同 PHP 版本行为的痛苦。因此,简短的回答是最重要的......

于 2013-02-28T10:40:47.147 回答
4

这是有关如何检索BIT列类型的完整示例:

<?php

$conn = new PDO('mysql:host=test;dbname=test', 'test', 'test');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

$res = $conn->query('SELECT my_bit, my_multiple_bit FROM test');
while($row = $res->fetch(PDO::FETCH_ASSOC)){
    var_dump($row);
}

...打印:

array(2) {
  ["my_bit"]=>
  string(1) "0"
  ["my_multiple_bit"]=>
  string(1) "7"
}
array(2) {
  ["my_bit"]=>
  string(1) "1"
  ["my_multiple_bit"]=>
  string(3) "128"
}

编辑#1:

这是我以前的代码,适用于 mysqli:

<?php

$conn = new mysqli('localhost', 'test', 'test','test');

$conn->query('DROP TABLE IF EXISTS bit_test');
$conn->query('CREATE TABLE bit_test (
    my_bit BIT(1) NULL,
    my_multiple_bit BIT(8) NULL
)');
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'0', b'111')");
$conn->query("INSERT INTO bit_test (my_bit, my_multiple_bit) VALUES (b'1', b'10000000')");

$res = $conn->query('SELECT my_bit, my_multiple_bit FROM test');
#while($row = mysqli_fetch_array($res, MYSQLI_ASSOC)){
while($row = $res->fetch_array(MYSQLI_ASSOC)){
    var_dump($row);
}

我得到了一个额外的数组项,所有值都设置为NULL(我不熟悉 mysqli,所以这可能是我的错),但输出在其他方面是相同的。我已经在 PHP/5.3.0 和 PHP/5.4.5 中对其进行了测试。

我建议您逐字尝试我的代码并验证您是否仍然得到%qu或奇怪的东西。我有一种强烈的感觉,这样的%qu绳子可能会从其他地方泄漏……

编辑#2:

从附加信息中,我认为我们可以得出以下结论:

  • 早期的 PHP 版本按原样检索BIT列,作为原始二进制字符串(0x07并且0x80是正确的数字,7并且128是十进制)。

  • 在某些时候,添加了自动编码,并BIT开始以小数形式检索列。

  • OP 使用的 PHP 版本可能在编码代码中有一个错误:%qu让我想起了 C printf 修饰符(尽管我找不到它的确切定义)。

鉴于不同的行为,需要一种解决方法来确保一致的输出:

  • CAST(my_bit AS UNSIGNED)生成一个十进制数
  • HEX(my_bit)生成一个十六进制数
于 2013-02-27T09:07:32.287 回答