【问题标题】:PDO and LOAD DATA LOCAL INFILE not workingPDO 和 LOAD DATA LOCAL INFILE 不起作用
【发布时间】:2012-11-19 12:59:48
【问题描述】:

我只是尝试将 LOAD DATA LOCL INFILE 与 pdo 一起使用。没有为我解决。这是我的功能

function connect($db_name,$db_host,$db_user,$db_pass)
{
    try
    {
        $this->connect = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);    
        $this->connect->exec("LOAD DATA LOCAL INFILE 'http://localhost/testoo.csv'
                                INTO TABLE 'parsed'
                                FIELDS TERMINATED BY ','
                                OPTIONALLY ENCLOSED BY '\"'
                                LINES TERMINATED BY '\n'
                                ('name','link','price','brand','imageurl')");

    }
    catch(PDOException $e) 
    {  
        echo $e->getMessage(); 
    }
}

现在什么都没有发生。相同的查询适用于普通的 mysql_query。这个问题的任何指针?

【问题讨论】:

  • 您是否收到任何错误消息?您是否开启了错误报告?
  • 感谢您,现在发现了错误! "PDO::exec() [pdo.exec]: 禁止加载数据本地文件"
  • Web 服务器中的文件不是我定义为本地文件的文件...它真的适用于旧版扩展吗?
  • <?php $server = "localhost"; $benutzername = "root"; $passwort = ""; $datenbank = "zanox"; mysql_connect($server,$benutzername,$passwort) or die ("No Connection"); mysql_select_db($datenbank) or die ("No Database found!"); // Datenbankanweisung $sql = "LOAD DATA LOCAL INFILE 'http://localhost/test1.csv' INTO TABLE de FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n' (name,link,price,brand,imageurl)"; $db = mysql_query($sql) or die (mysql_error()); ?> 这是我的旧代码。它工作正常
  • 如果这是一个一次性的 php ......只需从 CLI 客户端运行查询......完成并完成。 :-)

标签: php mysql pdo


【解决方案1】:

在 PDO 连接选项中设置属性PDO::MYSQL_ATTR_LOCAL_INFILE

function connect($db_name,$db_host,$db_user,$db_pass)
    {
        try
        {
            $this->connect = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass,array(PDO::MYSQL_ATTR_LOCAL_INFILE => true));    
            $this->connect->exec("LOAD DATA LOCAL INFILE 'http://localhost/testoo.csv'
                                    INTO TABLE 'parsed'
                                    FIELDS TERMINATED BY ','
                                    OPTIONALLY ENCLOSED BY '\"'
                                    LINES TERMINATED BY '\n'
                                    ('name','link','price','brand','imageurl')");

        }
        catch(PDOException $e) 
        {  
            echo $e->getMessage(); 
        }
    }

【讨论】:

  • 最佳答案侧重于使用实际 PDO。我的猜测是大多数用户在设置它时遇到问题,因为他们忘记允许自动增量字段......在 Jays 正确的示例中,如果有一个自动增量文件(很可能),让我们说调用 Table_ID 那么你应该添加“设置表 ID = NULL;"在字段条目之后
  • 我还建议结合上述内容阅读此答案,以帮助理解必要的设置:stackoverflow.com/questions/6017032/…
  • 非常感谢 :) 这确实是最好的解决方案。解决了我的问题。
【解决方案2】:

我遇到了同样的问题。我的 MySQL 服务器有正确的 local-infile conf,PHP/PDO 也有正确的 PDO::MYSQL_ATTR_LOCAL_INFILE conf。 解决方案是(重新)安装 php5-mysqlnd。

$> apt-get update
$> apt-get install php5-mysqlnd

...它成功了:)

【讨论】:

  • 这是唯一对我们有用的解决方案。谢谢
【解决方案3】:

2019 年编辑

7 年后 Sammitch 在这里说我最初的答案很糟糕。我什至无法弄清楚我在说什么“fgetcsv() 资源使用问题”。可能 7 年前的 PHP 缺少今天的一些 IO 流优化,但我愿意认为这是与 PHP 无关的资源限制。

Jay Dhameliya 下面的回答很可能是您想要的方式。LOAD DATA INFILE 应该尽快将数据直接发送到 mySQL。

为了完整起见,假设存在 阻止使用 LOAD DATA INFILE [例如最近发现的巨大安全漏洞] 并且您希望有效地从文件加载数据,您'我可能希望利用事务来批处理 IO 和索引写入。例如:

$fname = 'myfile.csv';

if( ! $fh = fopen($myfile, 'r') ) {
    throw new Exception("Could not open $fname for reading.");
}

$dbh = new PDO(...);
$dbh->beginTransaction();
$stmt = $dbh->prepare('INSERT INTO table VALUES (?,?,?,...)')
try {
    while( $params = fgetcsv($fh) ) {
        $stmt->execute($params);
    }
} catch( \PDOException $e ) {
    $dbh->rollBack();
    throw $e;
}
$dbh->commit();

将所有内容批处理到单个事务中仍然是LOAD DATA INFILE 如此之快的部分原因,也可能是@Benjamin 建议使用扩展插入的很大一部分。

原始答案

  1. LOAD DATA LOCAL INFILE forbidden in... PHP
  2. 确保 mySQL 和 www 用户都可以访问相关文件。

或者:使用fgetcsv() 并以编程方式创建插入。

编辑:

为了避免fgetcsv() 的资源使用问题[因为它试图一次读取整个文件],您可以创建一个类似于下面的循环来读取/插入可管理的块。

<?php
$fname = 'myfile.csv';
$chunksize = 50;

if( ! $fh = fopen($myfile, 'r') ) {
    throw new Exception("Could not open $fname for reading.");
}

$i=0;
$buffer = array()
while(!feof($fh)) {
    $buffer[] = fgets($fh);
    $i++;
    if( ($i % $chunksize) == 0 ) {
        commit_buffer($buffer);
        //run inserts
        $buffer = array(); //blank out the buffer.
    }
}

//clean out remaining buffer entries.
if( count($buffer) ) { commit_buffer($buffer); }

function commit_buffer($buffer) {
    foreach( $buffer as $line ) {
        $fields = explode(',', $line);
        //create inserts
    }
    //run inserts
    $buffer = array(); //blank out the buffer.
}

这样,在任何给定时间,只有$chunksize 行会保存在内存中。

您可能需要额外的代码来处理诸如包含逗号和换行符的封装字符串之类的事情,但如果您无法让 LOAD DATA LOCAL INFILE 工作,我看不到太多其他选择。

【讨论】:

  • 已经尝试过 1. 我的问题是,我有 80mb 之类的大文件,所以 fgetcsv() 会变慢
  • 那是因为它会首先尝试将所有 80MB 加载到 RAM 中。双重选择是使用 fgets() 加载 X 行,创建/运行插入,重复直到 EOF。
  • 这仍然会变慢。我必须定期导入 3.000.000+ 行的 CSV。我第一次尝试使用 foreach 循环和 fgets() 需要整晚,而 LOAD DATA LOCAL 只需几分钟即可完成工作。
  • @GielBerkers “将仍然”和“将” == 您的猜测。我想知道如果不是完全相同的事情,您想象 mySQL 客户端库对文件做了什么。此外,问题在于LOAD DATA 根本不起作用。
  • @Sammitch 如果您对此进行基准测试,您可能会对结果感到惊讶,这就是我在上面的链接中所做的!扩展插入总是会快得多。而且我确实在每种情况下都使用了事务和非模拟的准备好的语句!
猜你喜欢
  • 2018-03-04
  • 2013-12-12
  • 2016-07-31
  • 1970-01-01
  • 2012-06-01
  • 1970-01-01
  • 2012-10-05
  • 1970-01-01
相关资源
最近更新 更多