¿Cómo escapar de cadenas en SQL Server usando PHP?

89

Estoy buscando la alternativa de mysql_real_escape_string()SQL Server. ¿Es addslashes()mi mejor opción o hay otra función alternativa que se puede utilizar?

mysql_error()También sería útil una alternativa para .

Haga clic en Upvote
fuente
2
Para mí, no es una pregunta duplicada porque se refiere al caso específico de MSSQL que no tiene una DOP oficial relacionada
Pierre de LESPINAY

Respuestas:

74

addslashes()no es del todo adecuado, pero el paquete mssql de PHP no ofrece ninguna alternativa decente. La solución fea pero completamente general es codificar los datos como una cadena de bytes hexadecimal, es decir

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

Abstraído, eso sería:

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()equivalente es mssql_get_last_message().

caos
fuente
1
¡Vaya, es SELECT SCOPE_IDENTITY ()!
Bryan Rehbein
4
@genio: Mmm, genial, excepto que en realidad lo es. ¿Supongo que no explicaría cuál considera que es el problema?
caos
3
¿Has probado esto con columnas de fecha y hora? Recibo este error: SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.creo que este método puede ser correcto solo si funciona con todos los tipos de datos MSSQL.
Alejandro García Iglesias
1
El contenido de la mssql_escape()función devuelta no lo hace por mí. La pantalla de texto después de hacer una selección se ve 0x4a2761696d65206269656e206c652063686f636f6c6174así, ilegible.
Jeff Noel
3
@JeffNoel Probablemente esté envolviendo la cadena entre comillas simples o dobles. Dado que el elemento se escapa en hexadecimal, las comillas no son necesarias. Se supone que SQL Server convierte el valor hexadecimal en algo que la base de datos comprenda.
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;
    }

Parte del código aquí fue extraído de CodeIgniter. Funciona bien y es una solución limpia.

EDITAR: Hay muchos problemas con ese fragmento de código anterior. No use esto sin leer los comentarios para saber cuáles son. Mejor aún, no use esto en absoluto. Las consultas parametrizadas son tus amigos: http://php.net/manual/en/pdo.prepared-statements.php

genio
fuente
1
¿Por qué necesitas el preg_replace? ¿No es str_replacesuficiente?
Gabe
gabe: El preg_replace en este caso fue para permitirme usar los rangos que se me otorgan en las clases de caracteres de expresiones regulares. De lo contrario, habría muchas más sustituciones de cadenas en este.
genio
7
-1. No es responsabilidad de una función de cotización manipular los datos; todo lo que debe hacer es asegurarse de que la cadena tenga un formato tal que pueda agregarse a una declaración SQL y sobrevivir sin modificaciones.
cHao
6
Lo sentimos, pero esto es incorrecto desde la primera línea de código; empty($value)devolverá trueno solo para '', sino también para null, 0y '0'! Devolvería una cadena vacía en todos esos casos.
Nux
He votado a favor de esto, creo que es una función perfectamente buena siempre que sea plenamente consciente de los problemas anteriores. Sin embargo, lo llamaría ms_escape_and_strip_string, por lo que cualquier otra persona que trabaje en él verá que hace ambas tareas. Tener una cadena vacía devuelta en varios casos está bien siempre que la tenga en cuenta, a menos que me esté perdiendo un punto más importante aquí. Si esto no se ajusta a sus necesidades, siempre puede quitar esa línea y reemplazarla con la lógica que se adapte a sus necesidades.
NateDSaint
16

¿Por qué se molestaría en escapar de algo cuando puede utilizar parámetros en su consulta?

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

Funciona bien en selecciones, eliminaciones, actualizaciones independientemente de si los parámetros de sus valores lo son nullo no. Haga una cuestión de principio: no concatenar SQL y siempre estará seguro y sus consultas se leerán mucho mejor.

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

Konstantin
fuente
Este es el enfoque correcto. Siempre debe utilizar parámetros en lugar de consultas ad hoc. Sin embargo, el OP no utiliza los controladores sqlsrv. Está usando controladores mssql. por lo que el enlace a usar para aquellos de ustedes atascados usando controladores sqlsrv es http://php.net/manual/en/function.mssql-query.php .
smulholland2
1
@ smulholland2 ¿Quisiste decir "o aquellos de ustedes atascados usando controladores MSSQL "
Konstantin
Un escenario podría ser si desea generar un archivo de declaraciones INSERT para usar en un escenario de migración de datos.
Gary Reckard
11

Puede buscar en la biblioteca PDO . Puede usar declaraciones preparadas con PDO, que escapará automáticamente de cualquier carácter incorrecto en sus cadenas si hace las declaraciones preparadas correctamente. Esto es solo para PHP 5, creo.

alex
fuente
Con algunos de los comportamientos a medias que he visto en PDO, tendría que hacer algunas pruebas serias antes de confiar en que escapara todos los datos correctamente.
caos
@Caos ¿De verdad? No tengo conocimiento de esto ... ¿tiene un enlace a un artículo?
alex
En lo que estaba pensando era en el problema que este tipo estaba teniendo ayer con PDO. Cosas de transacciones no relacionadas, pero poco impresionantes. Combine eso con todo el historial de escapes de datos inadecuados en PHP (¡php.net le dice a la gente que use addedlashes ()!) Y me pongo muy sospechoso.
caos
2
Me encanta PDO y lo intenté primero, pero el de MSSQL (en Unix, basado en dblib) a veces me falla (falla de segmentación), por eso recurrí al mssql_escape definido anteriormente.
lapo
Gracias por tu comentario, @Iapo. Estaba considerando cambiarme a PDO para un proyecto mssql, específicamente para escapar, pero me ahorraste el problema.
Winfield Trail
4

Otra forma de manejar comillas simples y dobles es:

function mssql_escape($str)
{
    if(get_magic_quotes_gpc())
    {
        $str = stripslashes($str);
    }
    return str_replace("'", "''", $str);
}
Raja Bilal Ahmed
fuente
get_magic_quites_gpc ha sido DEPRECADO a partir de PHP 5.3.0 y ELIMINADO a partir de PHP 5.4.0. Ver php.net/manual/en/info.configuration.php#ini.magic-quotes-gpc
Ene
2

Para escapar de las comillas simples y dobles, debe duplicarlas:

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

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

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

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

etc ...

y atribución: carácter de escape en Microsoft SQL Server 2000

Marklark
fuente
2

Después de luchar con esto durante horas, se me ocurrió una solución que se siente casi mejor.

La respuesta de Chaos de convertir valores a cadenas hexadecimales no funciona con todos los tipos de datos, específicamente con columnas de fecha y hora.

Yo uso PHP PDO::quote(), pero como viene con PHP, PDO::quote()no es compatible con MS SQL Server y devuelve FALSE. La solución para que funcionara fue descargar algunos paquetes de Microsoft:

Después de eso, puede conectarse en PHP con PDO usando un DSN como el siguiente ejemplo:

sqlsrv:Server=192.168.0.25; Database=My_Database;

El uso de los parámetros UIDy PWDen el DSN no funcionó, por lo que el nombre de usuario y la contraseña se pasan como segundo y tercer parámetro en el constructor de PDO al crear la conexión. Ahora puedes usar PHP PDO::quote(). Disfrutar.

Alejandro García Iglesias
fuente
0

Advertencia: esta función fue ELIMINADA en PHP 7.0.0.

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

Para cualquiera que todavía use estas funciones mssql_ *, tenga en cuenta que se han eliminado de PHP a partir de la v7.0.0. Entonces, eso significa que eventualmente tendrá que reescribir el código de su modelo para usar la biblioteca PDO, sqlsrv_ *, etc. Si está buscando algo con un método de "cotización / escape", recomendaría PDO.

Las alternativas a esta función incluyen: PDO :: query (), sqlsrv_query () y odbc_exec ()

jjwdesign
fuente
0

Es mejor escapar también de las palabras reservadas SQL. Por ejemplo:

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
fuente
-1

He estado usando esto como una alternativa de 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));
Safeer Ahmed
fuente
-1

Para que la conversión vuelva a obtener los valores hexadecimales en SQL en ASCII, aquí está la solución que obtuve (usando la función del caos del usuario para codificar en hexadecimal)

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
fuente
-2

Se podría rodar su propia versión de mysql_real_escape_string, (y mejorarlo) con la siguiente expresión regular: [\000\010\011\012\015\032\042\047\134\140]. Eso se ocupa de los siguientes caracteres: nulo, retroceso, tabulación horizontal, nueva línea, retorno de carro, sustituto, comillas dobles, comillas simples, barra invertida, acento grave. El retroceso y la pestaña horizontal no son compatibles con mysql_real_escape_string.

Scott
fuente