Wie entkomme ich Strings in SQL Server mit PHP?

89

Ich suche nach einer Alternative mysql_real_escape_string()für SQL Server. Ist addslashes()meine beste Option oder gibt es eine andere alternative Funktion, die verwendet werden kann?

Eine Alternative für mysql_error()wäre auch nützlich.

Klicken Sie auf Upvote
quelle
2
Für mich ist es keine doppelte Frage, da es sich um den spezifischen MSSQL-Fall handelt, für den es keine verwandte offizielle gU gibt
Pierre de LESPINAY

Antworten:

74

addslashes()ist nicht völlig ausreichend, aber das mssql-Paket von PHP bietet keine anständige Alternative. Die hässliche, aber vollständig allgemeine Lösung besteht darin, die Daten als hexadezimalen Test zu codieren, d. H.

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

Abstrahiert wäre das:

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()Äquivalent ist mssql_get_last_message().

Chaos
quelle
1
Ups, es ist SELECT SCOPE_IDENTITY ()!
Bryan Rehbein
4
@genio: Mmm, großartig, außer es ist tatsächlich so. Ich nehme nicht an, dass Sie erklären würden, was Sie für das Problem halten?
Chaos
3
Haben Sie dies mit Datetime-Spalten versucht? Ich erhalte den folgenden Fehler: SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.Ich glaube, diese Methode kann nur korrekt sein, wenn sie mit jedem MSSQL-Datentyp funktioniert.
Alejandro García Iglesias
1
Der Inhalt der zurückgegebenen mssql_escape()Funktion erledigt dies nicht für mich. Die Textanzeige nach einer Auswahl sieht so aus und ist 0x4a2761696d65206269656e206c652063686f636f6c6174daher nicht lesbar.
Jeff Noel
3
@ JeffNoel Sie schließen die Zeichenfolge wahrscheinlich in einfache oder doppelte Anführungszeichen ein. Da das Element in hexadezimaler Form maskiert ist, sind die Anführungszeichen nicht erforderlich. SQL Server soll den Hex-Wert in etwas konvertieren, das die Datenbank versteht.
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;
    }

Ein Teil des Codes hier wurde von CodeIgniter abgerissen. Funktioniert gut und ist eine saubere Lösung.

BEARBEITEN: Es gibt viele Probleme mit dem obigen Code-Snippet. Bitte verwenden Sie dies nicht, ohne die Kommentare zu lesen, um zu wissen, um welche es sich handelt. Besser noch, bitte benutze das überhaupt nicht. Parametrisierte Abfragen sind Ihre Freunde: http://php.net/manual/en/pdo.prepared-statements.php

Genio
quelle
1
Warum brauchst du das preg_replace? Ist das nicht str_replaceausreichend?
Gabe
gabe: Der preg_replace in diesem Fall bestand darin, mir zu erlauben, die Bereiche zu verwenden, die mir in Zeichenklassen für reguläre Ausdrücke gewährt wurden. Andernfalls würde es in diesem Fall viel mehr Zeichenfolgen ersetzen.
Genio
7
-1. Es liegt nicht in der Verantwortung einer Anführungszeichenfunktion, Daten zu entstellen. Sie müssen lediglich sicherstellen, dass die Zeichenfolge in einem solchen Format vorliegt, dass sie einer SQL-Anweisung hinzugefügt werden kann und unverändert überlebt.
CHao
6
Sorry, aber das ist falsch von der ersten Zeile des Codes - empty($value)kehrt truenicht nur für '', sondern auch für die null, 0und '0'! In all diesen Fällen würden Sie eine leere Zeichenfolge zurückgeben.
Nux
Ich habe dies positiv bewertet, ich denke, es ist eine vollkommen gute Funktion, solange Sie sich der oben genannten Probleme voll bewusst sind. Ich würde es jedoch ms_escape_and_strip_string nennen, so dass jeder andere, der daran arbeitet, sehen würde, dass es beide Aufgaben erledigt. Die Rückgabe einer leeren Zeichenfolge in mehreren Fällen ist in Ordnung, solange Sie dies berücksichtigen, es sei denn, ich vermisse hier nur einen größeren Punkt. Wenn dies nicht Ihren Anforderungen entspricht, können Sie diese Zeile jederzeit entfernen und durch eine Logik ersetzen, die Ihren Anforderungen entspricht.
NateDSaint
16

Warum sollten Sie sich die Mühe machen, irgendetwas zu entkommen, wenn Sie Parameter in Ihrer Abfrage verwenden können?!

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

Es funktioniert direkt beim Auswählen, Löschen und Aktualisieren, unabhängig davon, ob Ihre Werteparameter sind nulloder nicht. Machen Sie eine Grundsatzfrage - Verketten Sie SQL nicht und Sie sind immer sicher und Ihre Abfragen lesen sich viel besser.

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

Konstantin
quelle
Dies ist der richtige Ansatz. Sie sollten im Gegensatz zu Ad-hoc-Abfragen immer Parameter verwenden. Das OP verwendet jedoch nicht die sqlsrv-Treiber. Er benutzt MSSQL-Treiber. Der Link für diejenigen unter Ihnen, die mit sqlsrv-Treibern nicht weiterkommen, lautet also http://php.net/manual/en/function.mssql-query.php .
smulholland2
1
@ smulholland2 Meinten Sie "oder diejenigen von Ihnen, die mit MSSQL- Treibern stecken geblieben sind "
Konstantin
Ein Szenario könnte sein, wenn Sie eine Datei mit INSERT-Anweisungen generieren möchten, die in einem Datenmigrationsszenario verwendet werden sollen.
Gary Reckard
11

Sie können in die PDO-Bibliothek schauen . Sie können vorbereitete Anweisungen mit PDO verwenden, die automatisch alle fehlerhaften Zeichen in Ihren Zeichenfolgen umgehen, wenn Sie die vorbereiteten Anweisungen korrekt ausführen. Dies ist nur für PHP 5, denke ich.

Alex
quelle
Bei einigen der halbherzigen Verhaltensweisen, die ich bei PDO gesehen habe, musste ich einige ernsthafte Tests durchführen, bevor ich darauf vertraute, dass alle Daten korrekt ausgeblendet wurden.
Chaos
@Chaos Wirklich? Mir ist das nicht bewusst. Haben Sie einen Link zu einem Artikel?
alex
Was ich dachte, war das Problem, das dieser Typ hier gestern mit PDO hatte. Nicht verwandtes Transaktionsmaterial, aber nicht beeindruckend. Kombiniere das mit der ganzen Geschichte von unzureichenden Daten, die in PHP entkommen (php.net sagt den Leuten, dass sie Addslashes () verwenden sollen!) Und ich werde sehr misstrauisch.
Chaos
2
Ich liebe PDO und habe es zuerst versucht, aber das für MSSQL (unter Unix, basierend auf dblib) schlägt manchmal bei mir fehl (Segmentierungsfehler), deshalb habe ich auf das oben definierte mssql_escape zurückgegriffen.
Lapo
Vielen Dank für Ihren Kommentar, @Iapo. Ich habe überlegt, für ein MSSQL-Projekt zu PDO zu wechseln - speziell, um zu entkommen -, aber Sie haben mir die Mühe erspart.
Winfield Trail
4

Eine andere Möglichkeit, einfache und doppelte Anführungszeichen zu verwenden, ist:

function mssql_escape($str)
{
    if(get_magic_quotes_gpc())
    {
        $str = stripslashes($str);
    }
    return str_replace("'", "''", $str);
}
Raja Bilal Ahmed
quelle
get_magic_quites_gpc wurde ab PHP 5.3.0 VERRINGERT und ab PHP 5.4.0 ENTFERNT. Siehe php.net/manual/en/info.configuration.php#ini.magic-quotes-gpc
Jan
2

Um einfache und doppelte Anführungszeichen zu vermeiden, müssen Sie sie verdoppeln:

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

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

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

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

etc...

und Zuordnung: Escape-Zeichen In Microsoft SQL Server 2000

Marklark
quelle
2

Nachdem ich stundenlang damit zu kämpfen hatte, habe ich eine Lösung gefunden, die sich fast am besten anfühlt.

Die Antwort von Chaos, Werte in Hexstring zu konvertieren, funktioniert nicht bei jedem Datentyp, insbesondere bei Datetime-Spalten.

Ich verwende PHPs PDO::quote(), aber da es mit PHP geliefert wird, PDO::quote()wird es für MS SQL Server nicht unterstützt und kehrt zurück FALSE. Die Lösung bestand darin, einige Microsoft-Bundles herunterzuladen:

Danach können Sie in PHP mit PDO über einen DSN wie im folgenden Beispiel eine Verbindung herstellen:

sqlsrv:Server=192.168.0.25; Database=My_Database;

Die Verwendung der Parameter UIDund PWDim DSN hat nicht funktioniert, daher werden Benutzername und Kennwort beim Erstellen der Verbindung als zweiter und dritter Parameter im PDO-Konstruktor übergeben. Jetzt können Sie PHPs verwenden PDO::quote(). Genießen.

Alejandro García Iglesias
quelle
0

Warnung: Diese Funktion wurde in PHP 7.0.0 ENTFERNT.

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

Beachten Sie für alle, die diese mssql_ * -Funktionen noch verwenden, dass sie ab Version 7.0.0 aus PHP entfernt wurden. Das bedeutet, dass Sie Ihren Modellcode eventuell neu schreiben müssen, um entweder die PDO-Bibliothek, sqlsrv_ * usw. zu verwenden. Wenn Sie etwas mit einer "Quoting / Escape" -Methode suchen, würde ich PDO empfehlen.

Alternativen zu dieser Funktion sind: PDO :: query (), sqlsrv_query () und odbc_exec ()

jjwdesign
quelle
0

Wenn Sie PDO verwenden, können Sie die PDO::quoteMethode verwenden.

Fredric Yeung
quelle
0

Es ist besser, auch SQL-reservierte Wörter zu umgehen. Beispielsweise:

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

Ich habe dies als Alternative verwendet von 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));
Sicherer Ahmed
quelle
-1

Für die Umwandlung der hexadezimalen Werte in SQL zurück in ASCII zu bekommen, hier ist die Lösung , die ich auf diese bekam (über die Funktion von Benutzern Chaos zu kodieren in hexadezimal)

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

Sie können Ihre eigene Version von mysql_real_escape_stringmit dem folgenden regulären Ausdruck rollen (und verbessern) : [\000\010\011\012\015\032\042\047\134\140]. Dabei werden die folgenden Zeichen berücksichtigt: Null, Rücktaste, horizontale Registerkarte, neue Zeile, Wagenrücklauf, Ersatz, doppeltes Anführungszeichen, einfaches Anführungszeichen, umgekehrter Schrägstrich, schwerwiegender Akzent. Rücktaste und horizontale Registerkarte werden von nicht unterstützt mysql_real_escape_string.

Scott
quelle