2014-06-15 10 views
5

Se si salvano i dati unicode in MSSQL è necessario salvare in un tipo di colonna nvarchar (et. Al) e si deve prefisso SQL STRING LITERALS con il capitale N. Se si utilizzano le istruzioni preparate, non è necessario prefisso valori con N.PHP, ORM, MSSQL e Unicode, è possibile realizzare questi lavori insieme?

inserto in TBL (Col) valori (N'hello ')

Se si utilizza un ORM come ZF DB, allora si stanno usando DOP conect a MSSQL (o si sta distribuendo su Windows , nel qual caso utilizzi SQLSRV o PDO_SQLSRV e tutto funzionerà e la mia domanda non ha più senso).

Se si utilizza una variante PDO che si collega a mssql (sybase, dblib, ecc.) Su Linux, allora non si ottengono istruzioni reali preparate, solo emulate.

Se è stato emulato istruzioni preparate, a livello filo, la SQL è completamente scritto con solo stringhe letterali e questo significa che è necessario far precedere qualsiasi valore unicode potenziale con N.

  1. E 'a tutti possibile anteporre automaticamente qualsiasi valore di char con N con ZF?
  2. Esistono ORM/librerie TableGateway che consentono questo tipo di manipolazione dei valori?
  3. C'è un modo per abilitare istruzioni preparate lato server da Linux?
  4. Qualcuno effettivamente esegue PHP di produzione da codice Linux e lo fa girare contro MSSQL? (Se sì, come si fa a trattare con Unicode?)

EDIT: posso ottenere unicode per salvare a MSSQL da Linux, ma l'aggiornamento del protocollo FreeTDS a 7/8 sembra rompere tutti i framework/librerie/ORM perché del requisito assoluto di modificare ciò che sarebbe normale SQL con il prefisso N. Non sono sicuro di come chiunque su Internet che afferma che l'aggiornamento alla versione 7/8 del protocollo abbia risolto i problemi Unicode, in realtà fa qualcosa oltre a scrivere ogni istruzione SQL in modo non portatile. Sembra che rimanere su Freetds 4.2 sia il modo migliore per gestire Unicode/UTF-8 e mssql.

risposta

6

Aggiornamento: Il driver non è più in anteprima. MS ha fornito le istruzioni ufficiali per la versione ora rilasciata: https://www.microsoft.com/en-us/sql-server/developer-get-started/php-ubuntu

Le istruzioni riportate di seguito non sono più aggiornate poiché MS ha scaricato il download del driver di anteprima.


Bene, c'è il driver ODBC fornito da Microsoft. Questo dovrebbe fornire un comportamento corretto a questo riguardo. Vedere la fine del post per come ho testato il suo comportamento (in modo preliminare). È stato testato su un database V12 di Azure SQL.

Come installare il driver Microsoft SQL ODBC su Ubuntu 16.04

Questo è stato testato su Ubuntu 16.04 fresca esempio Azure che si basa su l'immagine Azure Ubuntu 16.04 fornito da Canonical.Dopo il login, sono passato per l'utente root usando sudo -i, quindi:

apt-get update 
apt-get -y install atool make build-essential libc6 libkrb5-3 libgss3 e2fsprogs openssl equivs 
wget https://download.microsoft.com/download/2/E/5/2E58F097-805C-4AB8-9FC6-71288AB4409D/msodbcsql-13.0.0.0.tar.gz 
atool -x msodbcsql-13.0.0.0.tar.gz 
rm msodbcsql-13.0.0.0.tar.gz 

pushd msodbcsql-13.0.0.0/ 
./build_dm.sh --accept-warning | tee build_dm_result.txt 
command=$(cat build_dm_result.txt | grep "Run the command" | cut -d"'" -f2) 
rm build_dm_result.txt 
sh -c "$command" 
popd 

echo "/usr/lib64" > /etc/ld.so.conf.d/microsoft-lib64.conf 
ldconfig 

pushd msodbcsql-13.0.0.0/ 
./install.sh install --accept-license 

test è

sostituire il server e le credenziali nel seguente comando con la propria.

sqlcmd -S somedatabase.database.windows.net -U someuser -P somepassword 

Dovresti essere in grado di inviare comandi SQL a questo punto. Ok, facciamo funzionare con PHP.

usarlo con PHP

Dobbiamo assicurarci il pacchetto libodbc1 non è installato e che non otterrà installato, come sarebbe utilizzata da PHP al posto del nostro costume rispettato uno, e che porterebbe a problemi di codifica.

cat > libodbc1<<EOL 
Section: misc 
Priority: optional 
Standards-Version: 3.9.2 

Package: libodbc1 
Version: 9999 
Description: fake pkg, so that we satisfy the dependency of php7-odbc, so that we can keep our custom built libodbc 
EOL 

equivs-build libodbc1 
dpkg -i libodbc1_9999_all.deb 
rm libodbc1 
rm libodbc1_9999_all.deb 

apt-get install php7.0-odbc php7.0-cli 

A questo punto, dovrebbe essere disponibile come driver ODBC.

Testare il suo comportamento

Creare un file php, test.php con codifica UTF-8, e con il seguente contenuto. Sostituisci il server, il database e le credenziali nella stringa di connessione con il tuo.

<?php 

$pdo = new PDO('odbc:Driver={ODBC Driver 13 for SQL Server};Server=tcp:somedatabase.database.windows.net,1433;Database=somedatabase;[email protected];Pwd=somepassword;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;'); 

$str = 'Árvíztűrő tükörfúrógép, and... 你好,世界'; 

$pdo->prepare("DROP TABLE test")->execute(); 
$pdo->prepare("CREATE TABLE test(a NVARCHAR(MAX))")->execute(); 
$stmt = $pdo->prepare("INSERT INTO test VALUES(?)"); 
$stmt->bindParam(1, $str); 
$stmt->execute(); 

$stmt = $pdo->prepare("SELECT * FROM test"); 
$stmt->execute(); 
$data = $stmt->fetchall(); 
var_dump($data[0][0]==$str); //Returns true 

$stmt = $pdo->prepare("SELECT * FROM test WHERE a=?"); 
$stmt->bindParam(1, $str); 
$stmt->execute(); 
$data = $stmt->fetchall(); 
var_dump($data[0][0]==$str); //Returns true 

L'esecuzione di questo con php -f test.php mostra che otteniamo la corda senza alcun danneggiamento. Inoltre, la stringa sembra buona anche da SQL Server Management Studio. Ho osservato la seguente query nella pagina Performance Insight del portale di Azure: (@P1 nvarchar(max))INSERT INTO test VALUES(@P1), quindi le istruzioni preparate erano ovviamente utilizzate, quindi presumo che possa gestire il tuo (e il mio) scenario.

(Questo post è stato di grande aiuto durante il tentativo di arrivare a questo lavoro: http://www.codesynthesis.com/~boris/blog/2011/12/02/microsoft-sql-server-odbc-driver-linux/ Grazie Boris)

+0

Bummer, PDO :: lastInsertId non funziona, quindi questo è probabilmente un no-go con la maggior parte ORM. –

+0

Sono riuscito a modificare un ORM in modo che non tenti di utilizzare PDO :: lastInsertId, ma utilizza invece la clausola OUTPUT nelle istruzioni di inserimento per recuperare l'id. È stato un cambiamento sorprendentemente semplice. Tutto sembra buono per ora. –

+0

Ciao @Tarnay, è bello saperlo! Quale ORM hai modificato? Lavoro sui driver di Microsoft e vorrei saperne di più sul tuo problema e su come hai risolto il problema. –