Search code examples
phpmysqladdslashes

PHP's addslashes() not working for MySQL insert


I'm writing an import script in PHP to bring tables from SQL Server into MySQL, and I'm wrapping all char/varchar values in single-quotes for insertion. This works fine until the script encounters a value that has a single-quote in it. The obvious solution is to use addslashes(), but that isn't working for me. I also tried htmlspecialchars() as well as mysqli_real_escape_string, but neither worked. I've even tried removing the offending character altogether, using str_replace("'", "", $value) with no success. Finally, I tried wrapping the values in double- instead of single-quotes, but that gave me the same error upon encountering a row where the value's double-quotes could not be escaped.

Until the point of error, the script successfully inserts multiple chunks of 1,000 rows each, so I know the INSERT statement isn't formatted incorrectly. I logged the whole query and confirmed single-quotes aren't being escaped, although I can run an INSERT manually with just the offending row and a backslash included where necessary.

I'm stumped here. Are there any troubleshooting tips I've missed?

I have checked for duplicate or similar questions, but I'm not finding anything applicable to my situation that I haven't tried already. If I've overlooked a previous answer to this, please let me know.

Here's the code:

// Chunk size
$Insert_Max = 1000;
// Array to hold all rows for the insert
$Insert_Rows = [];  

while($row = mssql_fetch_row($result)) {
    $Insert_Vals = [];

    // Instead of building up a tedious string for each insert, let's do it programmatically
    $offset = 0;

    while ($offset < mssql_num_fields($result)) {
        $field_type = mssql_field_type($result, $offset);   

        if (empty($row[$offset])) {
            $Insert_Vals[] = "NULL";
        } else {
            if ($field_type == "int" || $field_type == "bit") {
                $Insert_Vals[] = $row[$offset];
            } else if (strpos($field_type, "char") !== false) { // Covers char, varchar, nvarchar
                $Insert_Vals[] = "'" . addslashes($row[$offset]) . "'";
            } else {
                $Insert_Vals[] = "'" . $row[$offset] . "'";
            }               
        }

        $offset++;
    }

    $Insert_String = "(" . implode(",", $Insert_Vals) . ")";

    $Insert_Rows[] = $Insert_String;

    $count++;
    if ($count >= $Insert_Max) {
        // $Insert_Header =  "INSERT INTO tablename (col1, etc.) VALUES "
        $internal_connection_object->Perform_The_Insert($Insert_Header, $Insert_Rows);
        $count = 0;
    }
}

Solution

  • The solution turned out to be simple: although the value was VARCHAR(255) on SQL Server, it was coming through to MySQL as TEXT. I saw this by appending (data type: $field_type) to each value in the insert. Accounting for TEXT in the VARCHAR conditional solved the problem.

    if ($field_type == "int" || $field_type == "bit") {
        $Insert_Vals[] = $row[$offset];
    } else if (strpos($field_type, "char") !== false || $field_type == "text") { 
        // Covers char, varchar, nvarchar, and now text
        $Insert_Vals[] = "'" . addslashes($row[$offset]) . "'";
    } else {
        $Insert_Vals[] = "'" . $row[$offset] . "'";
    }