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.

Cliquez sur Upvote
la source
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().

le chaos
la source
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

génio
la source
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

Konstantin
la source
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.

Alex
la source
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
4

Une autre façon de gérer les guillemets simples et doubles est:

function mssql_escape($str)
{
    if(get_magic_quotes_gpc())
    {
        $str = stripslashes($str);
    }
    return str_replace("'", "''", $str);
}
Raja Bilal Ahmed
la source
get_magic_quites_gpc a été DÉPRÉCIÉ à partir de PHP 5.3.0 et SUPPRIMÉ à partir de PHP 5.4.0. Voir php.net/manual/en/info.configuration.php#ini.magic-quotes-gpc
Jan
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

Marklark
la source
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.

Alejandro García Iglesias
la source
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 ()

jjwdesign
la source
0

Si vous utilisez PDO, vous pouvez utiliser la PDO::quoteméthode.

Fredric Yeung
la source
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);
BIM
la source
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;
}
Alex360
la source
-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));
Sûr Ahmed
la source
-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.

Scott
la source