Comment échapper aux chaînes dans SQL Server en utilisant PHP?


89

Je recherche l'alternative de mysql_real_escape_string()SQL Server. Est addslashes()ma meilleure option ou il y a une autre fonction alternative qui peut être utilisée?

Une alternative pour mysql_error()serait également utile.


2
Pour moi, ce n'est pas une question en double car elle concerne le cas MSSQL spécifique qui n'a pas d'AOP officielle liée
Pierre de LESPINAY

Réponses:


74

addslashes()n'est pas tout à fait adéquat, mais le package mssql de PHP ne fournit aucune alternative décente. La solution laide mais tout à fait générale consiste à encoder les données sous forme de chaîne d'octets hexadécimale, c'est-à-dire

$unpacked = unpack('H*hex', $data);
mssql_query('
    INSERT INTO sometable (somecolumn)
    VALUES (0x' . $unpacked['hex'] . ')
');

Résumé, ce serait:

function mssql_escape($data) {
    if(is_numeric($data))
        return $data;
    $unpacked = unpack('H*hex', $data);
    return '0x' . $unpacked['hex'];
}

mssql_query('
    INSERT INTO sometable (somecolumn)
    VALUES (' . mssql_escape($somevalue) . ')
');

mysql_error()l'équivalent est mssql_get_last_message().


1
Oups, c'est SELECT SCOPE_IDENTITY ()!
Bryan Rehbein

4
@genio: Mmm, super, sauf que c'est vraiment le cas. Je ne suppose pas que vous expliquiez ce que vous considérez comme le problème?
chaos

3
Avez-vous essayé cela avec des colonnes datetime? J'obtiens cette erreur: SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.je pense que cette méthode ne peut être correcte que si elle fonctionne avec tous les types de données MSSQL.
Alejandro García Iglesias

1
Le contenu de la mssql_escape()fonction retournée ne le fait pas pour moi. L'affichage du texte après avoir fait une sélection ressemble à ceci 0x4a2761696d65206269656e206c652063686f636f6c6174donc illisible.
Jeff Noel

3
@JeffNoel Vous encapsulez probablement la chaîne entre guillemets simples ou doubles. Puisque l'élément est échappé en hexadécimal, les guillemets ne sont pas nécessaires. SQL Server est censé convertir la valeur hexadécimale en quelque chose que la base de données comprend.
danielson317

40
function ms_escape_string($data) {
        if ( !isset($data) or empty($data) ) return '';
        if ( is_numeric($data) ) return $data;

        $non_displayables = array(
            '/%0[0-8bcef]/',            // url encoded 00-08, 11, 12, 14, 15
            '/%1[0-9a-f]/',             // url encoded 16-31
            '/[\x00-\x08]/',            // 00-08
            '/\x0b/',                   // 11
            '/\x0c/',                   // 12
            '/[\x0e-\x1f]/'             // 14-31
        );
        foreach ( $non_displayables as $regex )
            $data = preg_replace( $regex, '', $data );
        $data = str_replace("'", "''", $data );
        return $data;
    }

Une partie du code ici a été arrachée à CodeIgniter. Fonctionne bien et est une solution propre.

EDIT: Il y a beaucoup de problèmes avec cet extrait de code ci-dessus. Veuillez ne pas l'utiliser sans lire les commentaires pour savoir de quoi il s'agit. Mieux encore, ne l'utilisez pas du tout. Les requêtes paramétrées sont vos amis: http://php.net/manual/en/pdo.prepared-statements.php


1
Pourquoi avez-vous besoin du preg_replace? N'est-ce pas str_replacesuffisant?
Gabe

gabe: Le preg_replace dans ce cas était de me permettre d'utiliser les plages qui m'ont été offertes dans les classes de caractères d'expressions régulières. Il y aurait beaucoup plus de remplacements de chaînes dans celui-ci sinon.
genio

7
-1. Il n'est pas de la responsabilité d'une fonction de citation de modifier les données - tout ce qu'elle doit faire est de s'assurer que la chaîne est dans un format tel qu'elle puisse être ajoutée à une instruction SQL et survivre sans modification.
cHao

6
Désolé, mais c'est faux à partir de la première ligne de code - empty($value)retournera truenon seulement pour '', mais aussi pour null, 0et '0'! Vous renverriez une chaîne vide dans tous ces cas.
Nux

J'ai voté pour cela, je pense que c'est une fonction parfaitement correcte tant que vous êtes pleinement conscient des problèmes ci-dessus. Je l'appellerais ms_escape_and_strip_string cependant, donc toute autre personne travaillant dessus verrait qu'il effectue ces deux tâches. Avoir une chaîne vide retournée dans plusieurs cas est bien tant que vous en tenez compte, à moins que je ne manque juste un point plus important ici. Si cela ne correspond pas à vos besoins, vous pouvez toujours supprimer cette ligne et la remplacer par une logique qui répond à vos besoins.
NateDSaint

16

Pourquoi voudriez-vous échapper à quoi que ce soit lorsque vous pouvez utiliser des paramètres dans votre requête?!

sqlsrv_query(
    $connection, 
    'UPDATE some_table SET some_field = ? WHERE other_field = ?', 
    array($_REQUEST['some_field'], $_REQUEST['id'])
)

Cela fonctionne directement dans les sélections, les suppressions et les mises à jour, que vos paramètres de valeurs soient nullou non. Faites une question de principe - Ne concaténez pas SQL et vous êtes toujours en sécurité et vos requêtes se lisent beaucoup mieux.

http://php.net/manual/en/function.sqlsrv-query.php


C'est la bonne approche. Vous devez toujours utiliser des paramètres par opposition aux requêtes ad hoc. Cependant, l'OP n'utilise pas les pilotes sqlsrv. Il utilise des pilotes mssql. donc le lien à utiliser pour ceux d'entre vous bloqués à l'aide des pilotes sqlsrv est http://php.net/manual/en/function.mssql-query.php .
smulholland2

1
@ smulholland2 Vouliez-vous dire "ou ceux d'entre vous bloqués à l'aide de pilotes MSSQL "
Konstantin

Un scénario peut être si vous souhaitez générer un fichier d'instructions INSERT à utiliser dans un scénario de migration de données.
Gary Reckard

11

Vous pouvez consulter la bibliothèque PDO . Vous pouvez utiliser des instructions préparées avec PDO, qui échapperont automatiquement à tous les mauvais caractères de vos chaînes si vous exécutez correctement les instructions préparées. C'est pour PHP 5 seulement je pense.


Avec certains des comportements à moitié évités que j'ai vus de PDO, je devrais faire des tests sérieux avant de lui faire confiance pour échapper correctement à toutes les données.
chaos

@Chaos Vraiment? Je ne suis pas au courant de cela .. avez-vous un lien vers un article?
alex

Ce à quoi je pensais, c'était le problème que ce gars ici avait hier avec PDO. Trucs de transaction sans rapport, mais peu impressionnants. Combinez cela avec toute l'histoire des données inadéquates qui s'échappent en PHP (php.net disant aux gens d'utiliser des addlashes ()!) Et je deviens très suspect.
chaos

2
J'adore PDO et j'ai essayé ça en premier, mais celui pour MSSQL (sur Unix, basé sur dblib) échoue parfois sur moi (faute de segmentation), c'est pourquoi j'ai eu recours au mssql_escape défini ci-dessus.
lapo le

Merci pour votre commentaire, @Iapo. J'envisageais de passer à PDO pour un projet mssql - spécifiquement pour m'échapper - mais vous m'avez évité les ennuis.
Winfield Trail


2

Pour éviter les guillemets simples et doubles, vous devez les doubler:

$value = 'This is a quote, "I said, 'Hi'"';

$value = str_replace( "'", "''", $value ); 

$value = str_replace( '"', '""', $value );

$query = "INSERT INTO TableName ( TextFieldName ) VALUES ( '$value' ) ";

etc...

et attribution: caractère d'échappement dans Microsoft SQL Server 2000


2

Après avoir lutté avec cela pendant des heures, j'ai trouvé une solution qui semble presque la meilleure.

La réponse de Chaos concernant la conversion des valeurs en hexstring ne fonctionne pas avec tous les types de données, en particulier avec les colonnes datetime.

J'utilise PHP PDO::quote(), mais comme il est livré avec PHP, PDO::quote()n'est pas pris en charge pour MS SQL Server et renvoie FALSE. La solution pour que cela fonctionne était de télécharger des bundles Microsoft:

Après cela, vous pouvez vous connecter en PHP avec PDO en utilisant un DSN comme l'exemple suivant:

sqlsrv:Server=192.168.0.25; Database=My_Database;

L'utilisation des paramètres UIDet PWDdans le DSN ne fonctionnait pas, donc le nom d'utilisateur et le mot de passe sont passés comme deuxième et troisième paramètres sur le constructeur PDO lors de la création de la connexion. Vous pouvez maintenant utiliser PHP PDO::quote(). Prendre plaisir.



0

Attention: cette fonction a été SUPPRIMÉE dans PHP 7.0.0.

http://php.net/manual/en/function.mssql-query.php

Pour quiconque utilise encore ces fonctions mssql_ *, gardez à l'esprit qu'elles ont été supprimées de PHP à partir de la v7.0.0. Donc, cela signifie que vous devrez éventuellement réécrire le code de votre modèle pour utiliser la bibliothèque PDO, sqlsrv_ * etc. Si vous cherchez quelque chose avec une méthode "citant / échappant", je recommanderais PDO.

Les alternatives à cette fonction incluent: PDO :: query (), sqlsrv_query () et odbc_exec ()



0

Pour que la conversion récupère les valeurs hexadécimales en SQL en ASCII, voici la solution que j'ai obtenue (en utilisant la fonction du chaos utilisateur pour encoder en hexadécimal)

function hexEncode($data) {
    if(is_numeric($data))
        return $data;
    $unpacked = unpack('H*hex', $data);
    return '0x' . $unpacked['hex'];
}

function hexDecode($hex) {
    $str = '';
    for ($i=0; $i<strlen($hex); $i += 2)
        $str .= chr(hexdec(substr($hex, $i, 2)));
    return $str;
}

$stringHex = hexEncode('Test String');
var_dump($stringHex);
$stringAscii = hexDecode($stringHex);
var_dump($stringAscii);

0

Il est préférable d'échapper également aux mots réservés SQL. Par exemple:

function ms_escape_string($data) {
    if (!isset($data) or empty($data))
        return '';

    if (is_numeric($data))
        return $data;

    $non_displayables = array(
        '/%0[0-8bcef]/',        // URL encoded 00-08, 11, 12, 14, 15
        '/%1[0-9a-f]/',         // url encoded 16-31
        '/[\x00-\x08]/',        // 00-08
        '/\x0b/',               // 11
        '/\x0c/',               // 12
        '/[\x0e-\x1f]/',        // 14-31
        '/\27/'
    );
    foreach ($non_displayables as $regex)
        $data = preg_replace( $regex, '', $data);
    $reemplazar = array('"', "'", '=');
    $data = str_replace($reemplazar, "*", $data);
    return $data;
}

-1

J'utilise ceci comme alternative à mysql_real_escape_string():

function htmlsan($htmlsanitize){
    return $htmlsanitize = htmlspecialchars($htmlsanitize, ENT_QUOTES, 'UTF-8');
}
$data = "Whatever the value's is";
$data = stripslashes(htmlsan($data));

-2

Vous pouvez rouler votre propre version de mysql_real_escape_string(et l' améliorer) avec l'expression régulière suivante: [\000\010\011\012\015\032\042\047\134\140]. Cela prend en charge les caractères suivants: null, retour arrière, tabulation horizontale, nouvelle ligne, retour chariot, remplacement, guillemet double, guillemet simple, barre oblique inverse, accent grave. L'espace arrière et l'onglet horizontal ne sont pas pris en charge par mysql_real_escape_string.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.