PHP's addslashes() not working for MySQL insert

2.4k views Asked by At

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;
    }
}
1

There are 1 answers

0
abahler On BEST ANSWER

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] . "'";
}