Ошибка 500 после большого количества вызовов mysql_query в php - PullRequest
2 голосов
/ 18 ноября 2010

У меня есть скрипт php, который просматривает папку, содержащую файлы с разделителями табуляции, анализирует их построчно и вставляет данные в базу данных mysql. Я не могу использовать LOAD TABLE из-за ограничений безопасности на моем сервере, и у меня нет доступа к файлам конфигурации. Скрипт отлично работает при разборе 1 или 2 меньших файлов, но при работе с несколькими большими файлами я получаю ошибку 500. Похоже, что нет никаких журналов ошибок, содержащих сообщения, относящиеся к этой ошибке, по крайней мере, ни один, к которому мой хостинг-провайдер не дает мне доступ. Ниже приведен код, я также открыт для предложений альтернативных способов сделать то, что мне нужно сделать. В конечном итоге я хочу, чтобы этот сценарий запускался каждые 30 минут или около того, вставляя новые данные и удаляя файлы после завершения.

РЕДАКТИРОВАТЬ: После внесения изменений, предложенных Филом, сценарий все еще не работает, но у меня теперь есть следующее сообщение в моем журнале ошибок "mod_fcgid: тайм-аут чтения данных через 120 секунд", похоже, что сценарий истекает, любая идея, где можно изменить настройку тайм-аута?

$folder = opendir($dir);
    while (($file = readdir($folder)) !== false) {
        $filepath = $dir . "/" . $file;

        //If it is a file and ends in txt, parse it and insert the records into the db
        if (is_file($filepath) && substr($filepath, strlen($filepath) - 3) == "txt") {
            uploadDataToDB($filepath, $connection);
        }
    }

function uploadDataToDB($filepath, $connection) {
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);
    ini_set('max_execution_time', 300);

    $insertString = "INSERT INTO dirty_products values(";

    $count = 1;

    $file = @fopen($filepath, "r");

    while (($line = fgets($file)) !== false) {
        $values = "";
        $valueArray = explode("\t", $line);
        foreach ($valueArray as $value) {
            //Escape single quotes
            $value = str_replace("'", "\'", $value);
            if ($values != "")
                $values = $values . ",'" . $value . "'";
            else
                $values = "'" . $value . "'";
        }

        mysql_query($insertString . $values . ")", $connection);
        $count++;
    }

    fclose($file);

    echo "Count: " . $count . "</p>";
}

1 Ответ

1 голос
/ 18 ноября 2010

Первое, что я хотел бы сделать, - это использовать подготовленные операторы (используя PDO).

Используя функцию mysql_query(), вы создаете новый оператор для каждой вставки и можете превышать допустимый предел.

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

Пример

function uploadDataToDB($filepath, $connection) {
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);
    ini_set('max_execution_time', 300);

    $db = new PDO(/* DB connection parameters */);
    $stmt = $db->prepare('INSERT INTO dirty_products VALUES (
                         ?, ?, ?, ?, ?, ?)');
    // match number of placeholders to number of TSV fields

    $count = 1;

    $file = @fopen($filepath, "r");

    while (($line = fgets($file)) !== false) {
        $valueArray = explode("\t", $line);
        $stmt->execute($valueArray);
        $count++;
    }

    fclose($file);
    $db = null;

    echo "Count: " . $count . "</p>";
}

Учитывая, что вы хотите запустить этот скрипт напланируя, я бы полностью избегал веб-сервера и запускал скрипт через CLI, используя cron или любую другую службу планирования, которую предоставляет ваш хост.Это поможет вам избежать любого тайм-аута, настроенного на веб-сервере.

...