2016-02-24 25 views
5

SfondoImpossibile recuperare i dati varbinary da MSSQL

Ambiente di sviluppo:

PHP 7.0.3 con Apache 2.4.16 su Windows 10 x 64

SQL Server 2014 standard

Il sever ha FileStream abilitato su colonne di file corrispondenti.

provato ad installare sqlsvr driver, ma non riuscito a causa della mancanza di supporto per PHP7

SQL server di accesso da ODBC utilizzando il driver Codice SQL Server

PHP per inserire i dati delle immagini in MSSQL

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

Codice PHP per salvare i dati delle immagini da MSSQL

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

Il file viene caricato correttamente nel server SQL. Aprire la directory DATA di SQL Server, tutti i file caricati e può essere aperta da Paint.

Ma il recupero del file dal codice di salvataggio dell'immagine precedente è danneggiato. Nel file mancano alcuni byte dall'originale.

Metodo cercato

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

e anche il metodo indicato in questo collegamento.

Php with MSSQL display raw data from varbinary field

Ma entrambi non hanno fortuna, il file sembra anche essere danneggiato.

Qualsiasi aiuto è apprezzato.

Modifica 2016-02-25

Modificato l'istruzione SQL come il seguente, ma il file di output è ancora danneggiato.

$link->prepare("SELECT DATALENGTH([File]) AS [Size] , [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?"); 

Ora sto cercando di cambiare diversi driver ODBC di SQL Server per vedere se il file può produrre con successo.

Modifica 2016-08-09

Con il driver MSSQL DOP aggiornato per PHP 7. Tutto ha funzionato di nuovo con un fascino.

Ora, non abbiamo più bisogno di convert i dati varbinary utilizzando questo nuovo driver.

Reference Link

risposta

4

Quando si inseriscono nelle tabelle contengono varbinary, scegliere il tipo di dati è molto importante per PHP DOP.

PDO::PARAM_LOB è utilizzato invece utilizzare PDO::PARAM_STR per colonne del file

Per assicurarsi DB ha uscita il file corretto tramite il driver, convertire il campo VARBINARY(MAX) in stringa esadecimale e consegnarlo al PHP normalmente utilizzando questo metodo CONVERT(VARCHAR(MAX),[FileColumn],2)

Conversione della colonna in VARCHAR(MAX) anziché NVARCHAR(MAX) perché le stringhe HEX non necessitano di alcun supporto per Unicode e lasciano una stringa HEX semplice.

Quindi le stringhe esadecimali possono essere convertite da dati esadecimali in binari tramite la funzione PHP hex2bin() in modo efficiente.

La soluzione

$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"])); 

Informazioni aggiuntive

Quando si seleziona colonna varbinary da SQL Server Native Client 11.0 e ODBC Driver 11 for SQL Server, né convertire la colonna a varchar o no, PHP emette un risultato binario danneggiato non desiderato . Ma il driver SQL Server restituisce correttamente una stringa HEX quando sto convertendo la colonna in VARCHAR(MAX). Sospetto che questa azione sia un bug o un problema di driver.

+0

piangerò !! Ho avuto problemi con php pdo e dati varbinary provenienti da server mssql ... La tua risposta mi ha aiutato molto !! Posso inviare un e-abbraccio? : D Ora ... dove posso saperne di più su questo? Qual è il nome di questa "tecnica"? o qualcosa del genere, quindi posso google di più e ottenere più conoscenze – Frondor

+0

Sono felice che questo ti aiuti. Questo non è un tipo di tecnica, ho appena raggiunto questa soluzione per tentativi ed errori. Da quando ho scoperto che ci sono alcune segnalazioni di bug riguardanti i driver php e ODBC, i driver non emettono dati Unicode validi. Temo che anche i dati di 'varbinary' saranno elaborati come Unicode, quindi ho provato a convertirlo in una stringa hex che non sarà interpretata in modo falso dal driver. Dopo averlo provato, restituisco correttamente una stringa esadecimale valida in PHP. Quindi converto questo gruppo di stringhe in un file. Questo è il trucco. – MiKeNeko

+0

Quando abbiamo bloccato un tipo di dati, prova ad elaborarlo/codificarlo per renderlo testo normale. Questo è il trucco che ho fatto. – MiKeNeko

3

Se sei memorizzare dati binari non si convertono al NVARCHAR() quando selezionandolo - provare a rimuovere la CONVERT() da questo:

$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] = ?"); 

essere questo:

$stmt = $link->prepare("SELECT DATALENGTH([File]) AS [Size], [File] FROM [Attachment] WHERE [ModuleCde] = ? AND [AppID] = ? AND [Seq] = ? AND [StaffID] = ?"); 

Si desidera inoltre assicurarsi che la colonna sia VARBINARY(MAX).

Quando si inseriscono i dati penso che è necessario utilizzare SQLSRV_ENCODING_BINARY (invece di PDO::PARAM_STR)

+0

Grazie per si risponde, come non posso installare 'conducente sqlsvr' DOP così ho paura che non posso usare' SQLSRV_ENCODING_BINARY' – MiKeNeko

+0

@MiKeNeko, sarebbe 'PDO :: PARAM_LOB' essere più utile? Fornisce indizi su PDO e sul driver del database per gestire i dati in modo diverso anziché solo come stringhe. –

+0

@Ryan Vincent Grazie per il tuo suggerimento, ho riscontrato che il problema è un problema con il driver SQL e il problema è stato risolto. – MiKeNeko

-1
  1. Installare il server MSSQL
  2. Installare driver ODBC in base alla versione del sistema operativo e la versione di SQL Server, nonché ad esempio 64 bit vincere 10 e il server SQL 12 richiesti driver ODBC 11

    Scarica da questo link

  3. pdo_sqlsrv_.dll file scaricare in base alla versione php e incollare nella directory php/ext e aprire da php.ini estensioni porti sopra. ad esempio, nel mio caso, installa la versione xampp 3.2.2 che include php 7.08, per questo ho scaricato pdo_sqlsrv_7_ts.dll e impostato in base al precedente punto al punto 3.

    Scarica da questo link:

  4. Impostare il parametro di connessione al database in file PHP come

    $ conn = new PDO ("SQLSRV: server = 127.0.0.1,1433; Database = test" , "", "");
    $ conn-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);

Problemi correlati