PDO和LOAD DATA LOCAL INFILE无效

Joh*_*000 5 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(); 
    }
}
Run Code Online (Sandbox Code Playgroud)

现在没有任何反应.相同的查询适用于普通的mysql_query.这个问题有什么指针吗?

小智 12

PDO::MYSQL_ATTR_LOCAL_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,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(); 
        }
    }
Run Code Online (Sandbox Code Playgroud)


Sam*_*tch 4

2019 编辑

七年后,萨米奇在这里说我最初的答案很糟糕。我什至不明白我到底在谈论“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();
Run Code Online (Sandbox Code Playgroud)

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

原始总答案

  1. PHP 中禁止加载数据 LOCAL INFILE
  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.
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,$chunksize在任何给定时间只有行被保存在内存中。

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