php / php/php-src

PDO_DBLIB encodes passed binary data as a string, which is fragile

Abierto
#10,312 5 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Bug Extension: pdo_dblib Status: Needs Triage
Lenguaje dominante
C
Estrellas
40.4k
Forks
8.1k
Merge medio
2 d 13 h
PR fusionados (30 d)
96

Descripción

Description

A user reported an issue to me where they're trying to insert binary data (a PNG file, bound as a PARAM_LOB, inserting into a varbinary column) into an SQL Server database, and unexpectedly get a syntax error back.

It looks like PDO_DBLIB doesn't actually implement binding (no param hook is implemented), so it relies on PDO to do substitution and send the fully substituted query string back to the server (I assume this is a FreeTDS, or TDS protocol limitation. It's been a long, long time since I touched SQL Server...), instead of sending the query and parameters separate. The PDO parsing defers to the driver's quoter to turn the value into a string, escaping things like ' and \. However, it seems this isn't sufficient with binary data that could have things like nulls in the middle of the string.

The following code:

<?php
try {
    $image1 = base64_decode("..."); // a PNG image in this case
    $pdo = new PDO("dblib:host=SQLTEST;dbname=test", "sa", "...");
    if ($pdo) {
        $sql = "insert into dbo.TicketImage (TicketID, Image1, Image2) VALUES (168, ?, NULL)";
        $stmt = $pdo->prepare($sql);
        $stmt->bindParam(1, $image1, PDO::PARAM_LOB);
        $stmt->execute();
    }
} catch (PDOException $e) {
    var_dump($e);
}

Resulted in this output:

object(PDOException)#3 (8) {
  ["message":protected]=>
  string(165) "SQLSTATE[HY000]: General error: 20018 Incorrect syntax near ''. [20018] (severity 15) [insert into dbo.TicketImage (TicketID, Image1, Image2) VALUES (168, '�PNG
�
]"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  string(5) "HY000"
  ["file":protected]=>
  string(59) "/home/calvin/src/sqlserver/sql server binary blob issue.php"
  ["line":protected]=>
  int(16)
  ["trace":"Exception":private]=>
  array(1) {
    [0]=>
    array(5) {
      ["file"]=>
      string(59) "/home/calvin/src/sqlserver/sql server binary blob issue.php"
      ["line"]=>
      int(16)
      ["function"]=>
      string(7) "execute"
      ["class"]=>
      string(12) "PDOStatement"
      ["type"]=>
      string(2) "->"
    }
  }
  ["previous":"Exception":private]=>
  NULL
  ["errorInfo"]=>
  array(5) {
    [0]=>
    string(5) "HY000"
    [1]=>
    int(20018)
    [2]=>
    string(127) "Incorrect syntax near ''. [20018] (severity 15) [insert into dbo.TicketImage (TicketID, Image1, Image2) VALUES (168, '�PNG
�
]"
    [3]=>
    int(-1)
    [4]=>
    int(15)
  }
}

But I expected this output instead:

// success...

Other details

SQL Server version:

Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64) 
	Mar 18 2018 09:11:49 
	Copyright (c) Microsoft Corporation
	Express Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64> (Build 14393: ) (Hypervisor)

FreeTDS info:

Compile-time settings (established with the "configure" script)
                            Version: freetds v1.3.3
             freetds.conf directory: /etc
     MS db-lib source compatibility: yes
        Sybase binary compatibility: yes
                      Thread safety: yes
                      iconv library: yes
                        TDS version: auto
                              iODBC: no
                           unixodbc: yes
              SSPI "trusted" logins: no
                           Kerberos: yes
                            OpenSSL: no
                             GnuTLS: yes
                               MARS: yes

The provided table:

CREATE TABLE [dbo].[TicketImage](
       [TicketID] [int] NOT NULL,
       [Image1] [varbinary](max) NULL,
       [Image2] [varbinary](max) NULL,
CONSTRAINT [PK_TicketImage] PRIMARY KEY CLUSTERED
(
       [TicketID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
PHP Version

PHP 8.1.13

Operating System

Fedora 37

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza rastreando el manejo de parámetros de PDO_DBLIB y la ruta de sustitución de PDO descritos en el informe, incluido cómo el quoter del controlador gestiona los valores PARAM_LOB. Comprueba si la limitación de FreeTDS/TDS afecta al enfoque disponible. Se considera completado cuando el ejemplo PNG binario proporcionado se inserta en la columna varbinary sin un error de sintaxis y se ha identificado una cobertura de regresión adecuada.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
php, sql
Área
databases
Tipo de issue
Error
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Estancado
Claridad
Necesita aclaración
Aptitud para principiantes
30/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.