Импорт дампа SQL из PHP без использования exec () [duplicate]

У меня были похожие проблемы, и для небольших файлов вышеупомянутое решение Johannes Schaub работало как прелесть для меня.

Однако для файлов, которые немного больше, он столкнулся с проблемами с массивом символов предел компилятора. Поэтому я написал небольшое приложение кодировщика, которое преобразует содержимое файла в массив двумерных символов с одинаковыми размерами (и, возможно, нулями заполнения). Он создает выходные текстовые файлы с данными 2D-массива, такими как:

const char main_js_file_data[8][4]= {
    {'\x69','\x73','\x20','\0'},
    {'\x69','\x73','\x20','\0'},
    {'\x61','\x20','\x74','\0'},
    {'\x65','\x73','\x74','\0'},
    {'\x20','\x66','\x6f','\0'},
    {'\x72','\x20','\x79','\0'},
    {'\x6f','\x75','\xd','\0'},
    {'\xa','\0','\0','\0'}};

, где 4 фактически является переменной MAX_CHARS_PER_ARRAY в кодере. Затем файл с результирующим C-кодом, называемым, например, «main_js_file_data.h», может легко быть встроен в приложение C ++, например, следующим образом:

#include "main_js_file_data.h"

Вот исходный код кодировщика :

#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>


#define MAX_CHARS_PER_ARRAY 2048


int main(int argc, char * argv[])
{
    // three parameters: input filename, output filename, variable name
    if (argc < 4)
    {
        return 1;
    }

    // buffer data, packaged into chunks
    std::vector<char> bufferedData;

    // open input file, in binary mode
    {    
        std::ifstream fStr(argv[1], std::ios::binary);
        if (!fStr.is_open())
        {
            return 1;
        }

        bufferedData.assign(std::istreambuf_iterator<char>(fStr), 
                            std::istreambuf_iterator<char>()     );
    }

    // write output text file, containing a variable declaration,
    // which will be a fixed-size two-dimensional plain array
    {
        std::ofstream fStr(argv[2]);
        if (!fStr.is_open())
        {
            return 1;
        }
        const std::size_t numChunks = std::size_t(std::ceil(double(bufferedData.size()) / (MAX_CHARS_PER_ARRAY - 1)));
        fStr << "const char " << argv[3] << "[" << numChunks           << "]"    <<
                                            "[" << MAX_CHARS_PER_ARRAY << "]= {" << std::endl;
        std::size_t count = 0;
        fStr << std::hex;
        while (count < bufferedData.size())
        {
            std::size_t n = 0;
            fStr << "{";
            for (; n < MAX_CHARS_PER_ARRAY - 1 && count < bufferedData.size(); ++n)
            {
                fStr << "'\\x" << int(unsigned char(bufferedData[count++])) << "',";
            }
            // fill missing part to reach fixed chunk size with zero entries
            for (std::size_t j = 0; j < (MAX_CHARS_PER_ARRAY - 1) - n; ++j)
            {
                fStr << "'\\0',";
            }
            fStr << "'\\0'}";
            if (count < bufferedData.size())
            {
                fStr << ",\n";
            }
        }
        fStr << "};\n";
    }

    return 0;
}
6
задан PartisanEntity 7 June 2012 в 01:23
поделиться

2 ответа

Возможно с помощью mysqli_multi_query () .

Пример:

<?php

$mysqli = new mysqli($host, $user, $password, $database);

// create string of queries separated by ;
$query  = "INSERT INTO images (project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name) VALUES ('$project_id', '$user_id', '$image_name', '$date_created', '$link_to_file', '$thumbnail', '$ImageName');";
$query .= "INSERT INTO images_history (project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name, day, month, year) VALUES ('$project_id', '$user_id', '$image_name', '$date_created', '$link_to_file', '$thumbnail', '$ImageName', '$day', '$month', '$year');";

// execute query - $result is false if the first query failed
$result = mysqli_multi_query($mysqli, $query);

if ($result) {
    do {
        // grab the result of the next query
        if (($result = mysqli_store_result($mysqli)) === false && mysqli_error($mysqli) != '') {
            echo "Query failed: " . mysqli_error($mysqli);
        }
    } while (mysqli_more_results($mysqli) && mysqli_next_result($mysqli)); // while there are more results
} else {
    echo "First query failed..." . mysqli_error($mysqli);
}

Ключ в том, что вы должны используйте mysqli_multi_query, если вы хотите выполнить несколько запросов в одном вызове. По соображениям безопасности mysqli_query не будет выполнять несколько запросов, чтобы предотвратить инъекции SQL.

Также помните о поведении mysqli_store_result. Он возвращает FALSE, если запрос не имеет набора результатов (какие INSERT запросы не выполняются), поэтому вы также должны проверить mysqli_error, чтобы увидеть, что он возвращает пустую строку, означающую, что INSERT был успешным.

См. mysqli_multi_query mysqli_more_results mysqli_next_result mysqli_store_result

24
ответ дан drew010 19 August 2018 в 06:29
поделиться
  • 1
    Совершенно большое спасибо, это именно то направление, которое я хотел бы получить. – PartisanEntity 7 June 2012 в 01:57
  • 2
    Я так устал, но тем, кто все еще использует mysqli_multi_query, как @ dre010 объясняет: По соображениям безопасности mysqli_query не будет выполнять несколько запросов для предотвращения SQL-инъекций . Поэтому я думаю, что вам следует рассмотреть возможность разделить ваш запрос на несколько отдельных запросов и использовать подготовленный оператор – David 22 November 2015 в 03:35
  • 3
    Я смущен этим. Я пытаюсь адаптировать это, чтобы я мог сказать: «Если строка найдена путем поиска в первой таблице, верните результаты. Если он не найден путем поиска в первой таблице, и он не найден путем поиска во второй таблице, тогда вставьте его во вторую таблицу. ' Поэтому запустите первый оператор SELECT, но запустите только второй, если первый не возвращает никаких результатов. Есть ли способ различать, какой оператор SELECT вы хотите использовать в mysqli_multi_query? – Joshua Flood 27 June 2016 в 13:06
  • 4
    @DjDaihatsu Я бы сказал, не переусердствуйте с кодом и просто напишите два варианта в виде отдельных запросов и не используйте multi_select. В зависимости от ваших структур таблиц или списков выбора способ дифференцирования будет состоять в том, чтобы посмотреть, какие строки были возвращены в результате, и вы узнаете, из какого выражения он пришел, но который добавляет лишнюю логику, которой можно избежать, если вы просто сделаете два отдельные вызовы mysqli_query. – drew010 27 June 2016 в 15:31
  • 5
    Спасибо @ drew010! Таким образом, допустимо запускать несколько отдельных операторов выбора в разных таблицах в базе данных до закрытия соединения? Я, должно быть, сделал еще одну ошибку где-то в моем коде, поскольку мне не удается вернуть результаты из второй таблицы (в той же базе данных). – Joshua Flood 28 June 2016 в 09:43

Раз и навсегда! Используйте эту функцию для получения результатов по неограниченному количеству запросов в любом месте вашего скрипта.

Функция:

Вы просто передаете результат мультипроцесса функции, и это возвращает все результаты и ошибки, обнаруженные в каждом запросе.

  function loop_multi($result){
    //use the global variable $conn in this function
    global $conn;
    //an array to store results and return at the end
    $returned = array("result"=>array(),"error"=>array());
    //if first query doesn't return errors
      if ($result){
        //store results of first query in the $returned array
        $returned["result"][0] = mysqli_store_result($conn);
        //set a variable to loop and assign following results to the $returned array properly
        $count = 0;
        // start doing and keep trying until the while condition below is not met
        do {
            //increase the loop count by one
            $count++;
            //go to the next result
            mysqli_next_result($conn);
            //get mysqli stored result for this query
            $result = mysqli_store_result($conn);
            //if this query in the loop doesn't return errors
            if($result){
              //store results of this query in the $returned array
              $returned["result"][$count] = $result;
            //if this query in the loop returns errors
            }else{
              //store errors of this query in the $returned array
              $returned["error"][$count] = mysqli_error($conn);
            }
        }
        // stop if this is false
        while (mysqli_more_results($conn));
      }else{
        //if first query returns errors
        $returned["error"][0] = mysqli_error($conn);
      }
    //return the $returned array
    return $returned;
  }

Использование:

$query  = "INSERT INTO table1 (attribute1) VALUES ('value1');";
$query .= "INSERT INTO table2 (attribute2) VALUES ('value2');";
$query .= "SELECT * FROM table3;";

//execute query
$result = mysqli_multi_query($conn, $query);
//pass $result to the loop_multi function
$output = loop_multi($result);

Выход

$ включает в себя 2 массива «результат» и «результат», ошибка ", упорядоченная по запросу. Например, если вам нужно проверить, произошли ли какие-либо ошибки при выполнении третьего запроса и получить его результат, вы можете сделать:

if(isset($output['error'][2]) && $output['error'][2] !== ""){
  echo $output['error'][2];
}else{
  while($row = $output['result'][2]->fetch_assoc()) {
    print_r($row);
  }
}
0
ответ дан Kareem 19 August 2018 в 06:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: