Неправильный синтаксис рядом с ошибкой PK при попытке вставить в базу данных SQL сервера - PullRequest
0 голосов
/ 01 августа 2020

Исключение базы данных - yii \ db \ Exception

Error Info: Array
(
    [0] => HY000
    [1] => 102
    [2] => Incorrect syntax near 'PK'. [102] (severity 15) [INSERT INTO [ORDERS] ([ID], [STATUS], [ZIPFILE], [COLOR], [PRICE]) VALUES (87, 1,'PK]
    [3] => -1
    [4] => 15
)

↵ Причина: PDOException SQLSTATE [HY000]: Общая ошибка: 102 Неверный синтаксис рядом с 'PK'. [102] (серьезность 15) [INSERT INTO [ORDERS] ([ID], [STATUS], [ZIPFILE], [COLOR], [PRICE]) »ЗНАЧЕНИЯ (87, 1, 'PK]

В приложении yii2 я пытаюсь загрузить zip-файл с помощью функции file_get_uploads php, чтобы сначала преобразовать zip-файл в двоичный и сохранить его в столбце 'ZIPFILE' в базе данных SQL Server, но получаю указанное выше ошибка.

Похоже, что специальные символы после PK усекают значение ZIPFILE и все, что идет после него в строке вставки SQL. Если бы мне пришлось экранировать специальные символы, используя PHP addslashes(), я могу завершить вставку, но zip-файл повреждается из-за дополнительных косых черт. Изменение кодировки не является вариантом, поскольку я использую другое приложение для загрузки данных из базы данных, и это приложение требует, чтобы значения были в этой кодировке.

Есть ли способ избежать специальных символов, не повредив zip-файл?

Я включаю часть кода, чтобы сделать вещи немного понятнее arer.

Приложение использует структуру Yii2

Код контроллера

public function actionCreate()
{
    $model = new Orders();
    $model->load(Yii::$app->request->post())
   
    //populates ZIPFILE property with binary value of the ASCII encoded ZIPFILE string(pre-populated) compressed to a .zip file and read using file_get_contents in the Zip model
    $model->ZIPFILE = (new Zip)->asBinaryString($model->ZIPFILE);
    
    if ($model->save()) {
        return $this->redirect(['view', 'id' => $model->ID]);
    } else {
        return $this->render(
            'create', [
                'model' => $model,
            ]);
    }
}

В модели Zip

private string $_tempFolder = '/somecache/';

public function asBinaryString($content): ?string
    {
        $fileName = $this->create($content);
    
        $fileAsBinary = file_get_contents(Yii::$app->basePath . $this->_tempFolder . $fileName);
        
        return $fileAsBinary;   
    }

public function create($content): ?string
    {
        $zipName = \microtime();
        try {
            $zip = new \ZipArchive;
            if ($zip->open(Yii::$app->basePath . $this->_tempFolder . $zipName, \ZipArchive::CREATE) === true) {
                $zip->addFromString(time().'.RTF', $content);
                $zip->close();
            } else {
                throw new Exception(Yii::t('app', 'Archive could not be created in cache folder.'));
            }
        } catch (\Throwable $th) {
            throw $th; 
        } 
        return $zipName ?? null;
        
    }

Строка, загруженная обратно в $ model- > ZIPFILE выглядит так: "PKa��PM? ٟ�1590409143. RTFu��n�0�_e`���Os�R��j��� * �Ƅ�A" �5D ݨʻ� @ 0 ... ... "

Сохранение файла на диске со ссылкой в ​​базе данных невозможно, поскольку это расширение устаревшего приложения, которое требует, чтобы данные хранились в базе данных в виде zip-архива.

Попытка приблизиться к решению путем преобразования двоичного zip-файла в шестнадцатеричный с помощью PHP bin2hex (), но безуспешно. В шестнадцатеричном коде нет специальных символов; следовательно, модель $ сохраняется нормально, за исключением того, что zip-файл, сохраненный на сервере SQL, не может быть прочитан другим приложением.

Это не простая проблема Typo, и здесь была предпринята попытка использования подготовленных операторов, но не работает.

1 Ответ

0 голосов
/ 01 августа 2020

Мне потребовалось по крайней мере 10 дней обширного поиска в Интернете и тестирования различных решений, прежде чем это удалось решить.

Ответ на вышеуказанную проблему: для сохранения двоичной строки непосредственно в базе данных SQL Сервера. Файл должен быть отправлен в виде строки hex.

Решение:

public function asBinary($content): ?string
{
    $fileName = $this->create($content);
    $fileAsBinary = file_get_contents(Yii::$app->cache->cachePath . '/' . $fileName);
    return $fileAsBinary;   
}

/**
* zips file in cache folder into archive
*/
public function create($content): ?string
{
    $zipName = \microtime();
    try {
            $zip = new \ZipArchive;
            if ($zip->open(Yii::$app->cache->cachePath . '/'  . $zipName, \ZipArchive::CREATE) === true) {
                $zip->addFromString(time().'.RTF', $content);
                $zip->close();
            } else {
                throw new Exception(Yii::t('app', 'Archive could not be created in cache folder.'));
            }
    } catch (\Throwable $th) {
        throw $th;
    } 
    return $zipName ?? null;      
}

//return file as Hex string
public function asHex($content): string
{
    $fileAsBinary = $this->asBinary($content);
    $unpackedBinaryFile = unpack('H*hex', $fileAsBinary);
    $fileAsHex = '0x' . $unpackedBinaryFile['hex'];        
    return $fileAsHex;   
}

Заполнить ZIPFILE в $ model

$model->ZIPFILE = (new Zip)->asHex($model->ZIPFILE);

ZIP-файл должен быть преобразован в строку hex, которую можно напрямую сохранить на сервере SQL. SQL Сервер преобразует его в VARBINARY при вставке в базу данных.

По непонятным причинам я не смог передать ZIPFILE, используя подготовленные операторы Yii2. Каждый раз выдает ошибку. Также не удалось сохранить с помощью метода $model->save() ActiveRecord. Пришлось вставить, используя строку запроса SQL. Было бы здорово, если бы кто-нибудь мог сказать почему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...