【问题标题】:Inserting BIT(M) Column Values to MySQL5.7 with PHP7 MySQLi Prepared Statements使用 PHP7 MySQLi 准备语句将 BIT(M) 列值插入 MySQL5.7
【发布时间】:2018-03-13 21:17:59
【问题描述】:

当尝试使用 MySQLi 准备好的语句将值插入 BIT(64) 列时,我收到错误(执行时):

第 1 行的“bits64”列的数据太长

这是我的代码:

if ($Segments[0] == 'yes') {$bitmask = '1';}else{$bitmask = '0';}
if ($Segments[1] == 'yes') {$bitmask = $bitmask.'1';}else{$bitmask = $bitmask.'0';}
...
if ($Segments[63] == 'yes') {$bitmask = $bitmask.'1';}else{$bitmask = $bitmask.'0';}

$Upload = $conn->prepare("INSERT INTO `testtable` (`bits64`) VALUES (?)");
$Upload->bind_param("s", $bitmask);
$Upload->execute();

代码提供 64 个字符的字符串。如果我使用 PHPMyAdmin 插入相同的输出,它会成功运行,如下所示:

INSERT INTO `testtable` (`bits64`) VALUES (b'0000000000000000000000000000000000000000000000000000000000000000');
INSERT INTO `testtable` (`bits64`) VALUES (b'1111111111111111111111111111111111111111111111111111111111111111');

唯一显示任何“成功”(*不是真的)的事情是将绑定类型更改为整数。但它似乎被视为应该转换为二进制的整数,因为它给出了与设置为1 的位标志相同的错误。

我尝试过的其他方法包括将$bitmask 格式化为:

$bitmask = "b'".$bitmask."'";
$bitmask = "0b".$bitmask;
// And others 

据我所知,唯一的 bind_param 类型是整数、字符串、双精度和 blob。我假设它正在发送'101010'(代码示例)、101010(整数)、'b'101010'''0b101010' 等值;但是,需要的是b'101010'

出于速度和安全原因(其他领域),我必须使用准备好的语句。

我最初为此使用 BIGINT,但似乎在设置大多数标志时发生了舍入错误。

我想我禁用了 MySQL 严格模式。

我的后备方案是大量的 TINYINT 列或 CHAR(64),但我更喜欢更高效的存储。

这个网站上有一些相关的问题,但大多数都与单个位字段有关,其中整数 0 或 1 更容易与单个位相关联。我应该非常感谢任何建议或解决方案。

编辑

我意识到我没有完全空白的 SQL 模式。一旦 SQL 模式为空字符串,则不会出现错误,但无论我尝试什么都会得到 0111111111111111111111111111111111111111111111111111111111111111

编辑 2

通过设置了所有 1 个标志的 phpMyAdmin 插入也会给出0111111111111111111111111111111111111111111111111111111111111111,因此我配置此列的方式肯定存在其他问题。我使用的是 Ubuntu 16.04,服务器版本:5.7.19,PHP 版本:7.0.22。

【问题讨论】:

    标签: php mysql mysqli bindparam


    【解决方案1】:

    这是绑定类型很重要的示例之一...但对您的情况没有真正帮助。

    您需要了解您真正使用的数据类型。您已经在 PHP 中创建了一串数字。不是二进制数!这只是一个字符串。 PHP 可以对其进行处理和转换,但您需要明确说明您想要的是数字,而不是字符串。

    一种方法是:

    $bitmask = bindec($bitmask); // convert binary string to decimal number
    
    $Upload = $conn->prepare("INSERT INTO `testtable` (`bits64`) VALUES (?)");
    $Upload->bind_param("i", $bitmask); // bind as integer
    $Upload->execute();
    

    如果你想避免绑定为整数,你可以在 SQL 中使用VALUES(CAST(? AS UNSIGNED)) 或简单地添加 0,例如VALUES(? + 0)

    为避免使用bindec(),您可以在 PHP 中使用按位运算。该值将始终为整数。

    【讨论】:

      【解决方案2】:

      可以试试

      $Upload = $conn->prepare("INSERT INTO `testtable` (`bits64`) VALUES (b?)");
      

      但如果准备好的语句根本不支持位域,我不会感到惊讶..

      出于速度和安全原因(其他领域),我必须使用 准备好的语句。

      不,你没有。这同样安全:

      if(strlen(rtrim($bitmask,'01'))!==0){throw new \RuntimeException('illegal characters found in bitmask!');}
      $conn->query('INSERT INTO `testtable` (`bits64`) VALUES (b\''.$bitmask.'\')');
      

      我向您保证,性能影响绝对是最小的,对它进行基准测试。

      【讨论】:

      • Hanshenrik...感谢您的快速答复。我忘了提,我最初尝试过,但在 bind_param 出现了一个致命错误(即准备行不好)。不过,我可能做错了什么。
      猜你喜欢
      • 1970-01-01
      • 2017-04-10
      • 1970-01-01
      • 2014-03-16
      • 2014-03-29
      • 1970-01-01
      • 2016-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多