无法从 MSSQL 获取 varbinary 数据
Cannot fetch varbinary data from MSSQL
背景
开发环境:
PHP 7.0.3 与 Apache 2.4.16 在 Windows 10 x64
SQL 服务器 2014 标准版
服务器在相应的文件列上启用了 FileStream。
尝试安装 sqlsvr
驱动程序但由于缺少对 PHP7
的支持而失败
使用驱动程序 SQL Server
从 ODBC 访问 SQL 服务器
PHP 将图像数据插入 MS 的代码SQL
$link = @new \PDO("odbc:Driver={SQL Server};Server=$server;Database=$db", $user, $password);
$stmt = $link->prepare("INSERT INTO [Attachment] (AttID, Seq , ModuleCde, AppID, StaffID , FileName , [File]) VALUES ( NEWID() , ? , ? , ? , ? , ? , ? )");
$stmt->bindValue(1,$_POST["Seq"],PDO::PARAM_INT);
$stmt->bindValue(2,$_POST["ModuleCde"],PDO::PARAM_STR);
$stmt->bindValue(3,$_POST["AppID"],PDO::PARAM_STR);
$stmt->bindValue(4,$_SESSION["StaffID"],PDO::PARAM_STR);
$stmt->bindValue(5,$_FILES["file"]["name"][$_POST["Seq"]],PDO::PARAM_STR);
$stmt->bindValue(6,file_get_contents($_FILES["file"]["tmp_name"][$_POST["Seq"]]),PDO::PARAM_STR);
$stmt->execute();
PHP 从 MS 保存图像数据的代码SQL
$link = @new \PDO("odbc:Driver={SQL Server};Server=$server;Database=$db", $user, $password);
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size] , CONVERT(NVARCHAR(MAX),[File],2) AS [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
$stmt->bindValue(1,$_GET["ModuleCde"],PDO::PARAM_STR);
$stmt->bindValue(2,$_GET["AppID"],PDO::PARAM_STR);
$stmt->bindValue(3,$_GET["Seq"],PDO::PARAM_STR);
$stmt->bindValue(4,$_SESSION["StaffID"],PDO::PARAM_STR);
$stmt->execute();
$stmt->bindColumn(2,$img,PDO::PARAM_LOB, 0);
$stmt->fetch(PDO::FETCH_ASSOC);
file_put_contents( "file" , $img );
文件已成功上传到SQL服务器。打开SQL服务器的DATA
目录,所有上传的文件都可以用画图打开。
但是从上面的图像保存代码中提取的文件已损坏。该文件缺少原始文件中的一些字节。
尝试过的方法
fwrite( fopen("file","w+") , strtolower("0x".str_replace("[=12=]","",$img)) );
还有这个link.
中所述的方法
Php with MSSQL display raw data from varbinary field
但都没有运气,文件似乎也已损坏。
感谢任何帮助。
编辑 2016-02-25
修改SQL语句如下,但输出文件仍然损坏。
$link->prepare("SELECT DATALENGTH([File]) AS [Size] , [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
我现在正在尝试更换不同的SQL服务器ODBC驱动,看看文件能否输出成功。
编辑 2016-08-09
使用更新后的 MSSQL PHP 7 的 PDO 驱动程序。一切顺利地再次运行。
现在,我们不再需要 convert
使用这个新驱动程序的 varbinary 数据。
如果您要存储二进制数据,请在选择它时不要将其转换为 NVARCHAR()——尝试从中删除 CONVERT():
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size] , CONVERT(NVARCHAR(MAX),[File],2) AS [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
是这样的:
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size], [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
您还想确保您的列是 VARBINARY(MAX)
。
插入数据时,我认为您需要使用 SQLSRV_ENCODING_BINARY
(而不是 PDO::PARAM_STR
)
当插入包含 varbinary 的表时,数据类型的选择对 PHP PDO 非常重要。
应使用 PDO::PARAM_LOB
而不是对文件列使用 PDO::PARAM_STR
为确保DB通过驱动程序输出了正确的文件,将VARBINARY(MAX)
字段转换为十六进制字符串,然后使用此方法将其正常交给PHPCONVERT(VARCHAR(MAX),[FileColumn],2)
将列转换为 VARCHAR(MAX)
而不是 NVARCHAR(MAX)
,因为 HEX 字符串不需要任何 Unicode 支持并保留纯 HEX 字符串。
然后可以通过 PHP 函数 hex2bin()
有效地将十六进制字符串从十六进制数据转换回二进制数据。
解决方案
$link = @new \PDO("odbc:Driver={SQL Server};Server=$server;Database=$db", $user, $password);
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size] , CONVERT(VARCHAR(MAX),[File],2) AS [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
$stmt->bindValue(1,$_GET["ModuleCde"],PDO::PARAM_STR);
$stmt->bindValue(2,$_GET["AppID"],PDO::PARAM_STR);
$stmt->bindValue(3,$_GET["Seq"],PDO::PARAM_STR);
$stmt->bindValue(4,$_SESSION["StaffID"],PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
file_put_contents( "file" , hex2bin($result["File"]) );
附加信息
从 SQL Server Native Client 11.0
和 ODBC Driver 11 for SQL Server
中选择 varbinary 列时,无论是否将列转换为 varchar
,PHP 都会输出损坏的二进制结果,这是不需要的。但是当我将列转换为 VARCHAR(MAX)
时,驱动程序 SQL Server
成功 return 给我一个 HEX 字符串。我怀疑此操作是错误或驱动程序问题。
背景
开发环境:
PHP 7.0.3 与 Apache 2.4.16 在 Windows 10 x64
SQL 服务器 2014 标准版
服务器在相应的文件列上启用了 FileStream。
尝试安装 sqlsvr
驱动程序但由于缺少对 PHP7
使用驱动程序 SQL Server
PHP 将图像数据插入 MS 的代码SQL
$link = @new \PDO("odbc:Driver={SQL Server};Server=$server;Database=$db", $user, $password);
$stmt = $link->prepare("INSERT INTO [Attachment] (AttID, Seq , ModuleCde, AppID, StaffID , FileName , [File]) VALUES ( NEWID() , ? , ? , ? , ? , ? , ? )");
$stmt->bindValue(1,$_POST["Seq"],PDO::PARAM_INT);
$stmt->bindValue(2,$_POST["ModuleCde"],PDO::PARAM_STR);
$stmt->bindValue(3,$_POST["AppID"],PDO::PARAM_STR);
$stmt->bindValue(4,$_SESSION["StaffID"],PDO::PARAM_STR);
$stmt->bindValue(5,$_FILES["file"]["name"][$_POST["Seq"]],PDO::PARAM_STR);
$stmt->bindValue(6,file_get_contents($_FILES["file"]["tmp_name"][$_POST["Seq"]]),PDO::PARAM_STR);
$stmt->execute();
PHP 从 MS 保存图像数据的代码SQL
$link = @new \PDO("odbc:Driver={SQL Server};Server=$server;Database=$db", $user, $password);
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size] , CONVERT(NVARCHAR(MAX),[File],2) AS [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
$stmt->bindValue(1,$_GET["ModuleCde"],PDO::PARAM_STR);
$stmt->bindValue(2,$_GET["AppID"],PDO::PARAM_STR);
$stmt->bindValue(3,$_GET["Seq"],PDO::PARAM_STR);
$stmt->bindValue(4,$_SESSION["StaffID"],PDO::PARAM_STR);
$stmt->execute();
$stmt->bindColumn(2,$img,PDO::PARAM_LOB, 0);
$stmt->fetch(PDO::FETCH_ASSOC);
file_put_contents( "file" , $img );
文件已成功上传到SQL服务器。打开SQL服务器的DATA
目录,所有上传的文件都可以用画图打开。
但是从上面的图像保存代码中提取的文件已损坏。该文件缺少原始文件中的一些字节。
尝试过的方法
fwrite( fopen("file","w+") , strtolower("0x".str_replace("[=12=]","",$img)) );
还有这个link.
中所述的方法Php with MSSQL display raw data from varbinary field
但都没有运气,文件似乎也已损坏。
感谢任何帮助。
编辑 2016-02-25
修改SQL语句如下,但输出文件仍然损坏。
$link->prepare("SELECT DATALENGTH([File]) AS [Size] , [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
我现在正在尝试更换不同的SQL服务器ODBC驱动,看看文件能否输出成功。
编辑 2016-08-09
使用更新后的 MSSQL PHP 7 的 PDO 驱动程序。一切顺利地再次运行。
现在,我们不再需要 convert
使用这个新驱动程序的 varbinary 数据。
如果您要存储二进制数据,请在选择它时不要将其转换为 NVARCHAR()——尝试从中删除 CONVERT():
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size] , CONVERT(NVARCHAR(MAX),[File],2) AS [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
是这样的:
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size], [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
您还想确保您的列是 VARBINARY(MAX)
。
插入数据时,我认为您需要使用 SQLSRV_ENCODING_BINARY
(而不是 PDO::PARAM_STR
)
当插入包含 varbinary 的表时,数据类型的选择对 PHP PDO 非常重要。
应使用PDO::PARAM_LOB
而不是对文件列使用 PDO::PARAM_STR
为确保DB通过驱动程序输出了正确的文件,将VARBINARY(MAX)
字段转换为十六进制字符串,然后使用此方法将其正常交给PHPCONVERT(VARCHAR(MAX),[FileColumn],2)
将列转换为 VARCHAR(MAX)
而不是 NVARCHAR(MAX)
,因为 HEX 字符串不需要任何 Unicode 支持并保留纯 HEX 字符串。
然后可以通过 PHP 函数 hex2bin()
有效地将十六进制字符串从十六进制数据转换回二进制数据。
解决方案
$link = @new \PDO("odbc:Driver={SQL Server};Server=$server;Database=$db", $user, $password);
$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size] , CONVERT(VARCHAR(MAX),[File],2) AS [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?");
$stmt->bindValue(1,$_GET["ModuleCde"],PDO::PARAM_STR);
$stmt->bindValue(2,$_GET["AppID"],PDO::PARAM_STR);
$stmt->bindValue(3,$_GET["Seq"],PDO::PARAM_STR);
$stmt->bindValue(4,$_SESSION["StaffID"],PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
file_put_contents( "file" , hex2bin($result["File"]) );
附加信息
从 SQL Server Native Client 11.0
和 ODBC Driver 11 for SQL Server
中选择 varbinary 列时,无论是否将列转换为 varchar
,PHP 都会输出损坏的二进制结果,这是不需要的。但是当我将列转换为 VARCHAR(MAX)
时,驱动程序 SQL Server
成功 return 给我一个 HEX 字符串。我怀疑此操作是错误或驱动程序问题。