无法从MSSQL

时间:2016-02-24 07:53:51

标签: php sql-server pdo sql-server-2014 php-7

背景

开发环境:

在Windows 10 x64上使用Apache 2.4.16的PHP 7.0.3

SQL Server 2014标准

服务器在相应的文件列上启用了FileStream。

尝试安装sqlsvr驱动程序,但由于缺乏对PHP7的支持而失败

使用驱动程序SQL Server

从ODBC访问SQL Server

用于将图像数据插入MSSQL的PHP​​代码

$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();

用于保存MSSQL图像数据的PHP代码

$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 Server的DATA目录,所有上传的文件都可以通过Paint打开。

但是从上面的图像保存代码获取的文件已损坏。该文件缺少原始文件中的一些字节。

尝试方法

fwrite( fopen("file","w+") , strtolower("0x".str_replace("\0","",$img)) );

以及此链接中所述的方法。

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 Server ODBC驱动程序,以查看该文件是否可以成功输出。

编辑2016-08-09

使用更新的PHP 7 MSSQL PDO驱动程序。一切都有魅力。

现在,使用这个新驱动程序,我们不再需要convert varbinary数据了。

Reference Link

3 个答案:

答案 0 :(得分:4)

当插入包含varbinary的表时,选择数据类型对PHP PDO非常重要。

PDO::PARAM_LOB将使用PDO::PARAM_STR代替文件列

要确保数据库通过驱动程序输出正确的文件,请将VARBINARY(MAX)字段转换为十六进制字符串,然后使用此方法将其移交给PHP CONVERT(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.0ODBC Driver 11 for SQL Server中选择varbinary列时,既不将列转换为varchar,也不会输出损坏的二进制结果,这是不需要的。但是当我将列转换为SQL Server时,驱动程序VARCHAR(MAX)成功地向我返回了一个HEX字符串。我怀疑这个动作是一个错误或驱动程序问题。

答案 1 :(得分:3)

如果您要存储二进制数据,请在选择时将其转换为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

答案 2 :(得分:-1)

  1. 安装MSSQL服务器
  2. 根据操作系统版本和SQL Server版本安装ODBC驱动程序 例如64位胜利10和SQL服务器12需要odbc驱动程序11

    从此链接下载

  3. pdo_sqlsrv_.dll文件根据php版本下载并粘贴到php / ext目录并从php.ini扩展部分打开。例如, 在我的情况下安装包含php 7.08的xampp 3.2.2版本 这个我下载pdo_sqlsrv_7_ts.dll并根据上面设置 在第3点提到。

    从此链接下载:

  4. 在PHP文件中设置数据库连接参数,如

    $ conn = new PDO(&#34; sqlsrv:server = 127.0.0.1,1433; Database = test&#34;,&#34;&#34;,&#34;&#34;); <登记/> $ conn-&GT;的setAttribute(PDO :: ATTR_ERRMODE,PDO :: ERRMODE_EXCEPTION);