PDO和LOAD DATA LOCAL INFILE无法正常工作

时间:2012-11-19 12:59:49

标签: php mysql pdo

我只是尝试使用带有pdo的LOAD DATA LOCL 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);    
        $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。这个问题有什么指针吗?

3 个答案:

答案 0 :(得分:11)

在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(); 
        }
    }

答案 1 :(得分:4)

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

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

......它有效:)

答案 2 :(得分: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用户都可以访问相关文件。
  3. 或者:使用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工作,我看不到其他选择。