使用PHP PDO逐行插入CSV到Postgres

时间:2013-05-17 22:28:29

标签: php postgresql csv pdo insert-into

我正在尝试让用户上传文件,然后将该文件逐行插入到postgres数据库中。

我有这段代码,我的语法出现以下错误:

  

数组([0] => 42601 [1] => 7 [2] =>错误:语法错误在或接近   “”INSERT INTO“”第1行:“插入”公共“。”tblSedimentGrabEvent“   价值('A1000'...... ^)

我一直在查看PHP PDO手册和Postgres网站,以及搜索错误代码但仍然没有成功。我知道它可能很小但它让我感到难过。

<?php
try { 
    $db = new PDO("pgsql:dbname=name;host=host","user","pass");
}   
catch(PDOException $e) {
    echo $e->getMessage();
}

if ($_FILES["file"]["error"] > 0)
{
    echo "Error: " . $_FILES["file"]["error"] . "<br>";
}
else
{
    echo "Uploaded Successfully!<br>";
    echo "File Name: " . $_FILES["file"]["name"] . "<br>";
    echo "Type: " . $_FILES["file"]["type"] . "<br>";
    echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
    echo "Temp file: " . $_FILES["file"]["tmp_name"]. "<br>";
    {
        move_uploaded_file($_FILES["file"]["tmp_name"],
        "D:/Apapub/public_html/databases/B13/temp/" . $_FILES["file"]["name"]);
        echo "Stored in: " . "D:\Apapub\public_html\databases\B13\temp" . $_FILES["file"]["name"]. "<br>";
    }

 }

$file_handle = fopen("D:/Apapub/public_html/databases/B13/temp/grabevents.txt", "r");

while (!feof($file_handle) ) {

    $text_file = fgetcsv($file_handle);

    print_r($text_file);

    $query=<<<eof
"INSERT INTO "public"."tblSedimentGrabEvent" VALUES ('$text_file[0]','$text_file[1]','$text_file[2]','$text_file[3]','$text_file[4]','$text_file[5]','$text_file[6]','$text_file[7]','$text_file[8]','$text_file[9]','$text_file[10]','$text_file[11]','$text_file[12]','$text_file[13]','$text_file[14]','$text_file[15]','$text_file[16]','$text_file[17]','$text_file[18]','$text_file[19]','$text_file[20]','$text_file[21]','$text_file[22]','$text_file[23]')"
    eof;
    $sth = $db->query($query);
}
if (!$sth) {
    echo "<p>\nPDO::errorInfo():\n</p>";
    print_r($db->errorInfo());
} 
fclose($file_handle);

echo "<p><b>Records Imported</b></p>";

?>

以下是示例数组:

A1000,24,M,28/Mar/2013,11:45:27,1,SCCWRP,Singel Van Veen,33.1234,-118.523,AGPS,12,cm,Olive Green,Sand,None,Yes,No,No,No,None,Test Record # 1,No,22/May/2013
A1000,24,M,28/Mar/2013,11:45:27,1,SCCWRP,Singel Van Veen,33.1334,-118.543,AGPS,12,cm,Olive Green,Sand,None,Yes,No,No,No,None,Test Record # 1,No,15/May/2013
A1000,24,M,28/Mar/2013,11:56:33,2,SCCWRP,Single Van Veen,33.1635,-118.593,AGPS,12,cm,Olive Green,Sand,None,No,Yes,No,No,None,Test Record #2,No,15/May/2013
A1000,24,M,28/Mar/2013,12:06:33,3,SCCWRP,Single Van Veen,33.1534,-118.563,AGPS,12,cm,Olive Green,Sand,None,No,No,Yes,No,None,Test Record #3,No,15/May/2013
A1000,24,M,28/Mar/2013,12:12:33,4,SCCWRP,Single Van Veen,33.1034,-118.503,AGPS,12,cm,Olive Green,Sand,None,No,No,No,yes,None,Test Record #4,No,15/May/2013

我成功使用COPY命令但我的主管希望它逐行解析以便稍后运行一些检查

!! ANSWER !!

我不知道如何给@Spudley提供道具,但他帮助我回答了这个问题。

在做了他说的话之后我发现我不需要查询周围的引号(我猜它因为我正在使用heredoc?)。

这很有用(但是:由Craig Ringer编辑,这仍然是危险的不安全因素,不应该使用,不要将其复制为示例代码):

$query=<<<eof
INSERT INTO "public"."tblSedimentGrabEvent" VALUES ('$text_file[0]','$text_file[1]','$text_file[2]','$text_file[3]','$text_file[4]','$text_file[5]','$text_file[6]','$text_file[7]','$text_file[8]','$text_file[9]','$text_file[10]','$text_file[11]','$text_file[12]','$text_file[13]','$text_file[14]','$text_file[15]','$text_file[16]','$text_file[17]','$text_file[18]','$text_file[19]','$text_file[20]','$text_file[21]','$text_file[22]','$text_file[23]')
eof;
$sth = $db->query($query);

再次感谢!

2 个答案:

答案 0 :(得分:1)

对SQL进行文本替换是容易出错,不安全,难以调试和糟糕的风格。使用PDO或pg_query_params的参数化语句。你的“回答”是完全不安全的,请不要使用它。

这不仅可以解决您的问题,还可以保护您免受包括SQL注入在内的各类严重安全漏洞的侵害。请参阅wikipediabobby tablesPHP manual

另见this prior answer

当你在这里时,考虑使用效率更高的COPY来直接将CSV流式传输到PostgreSQL中的表中。请参阅pg_copy_from或更低级pg_put_line功能。

答案 1 :(得分:0)

我从这个页面得到了答案: PHP PDO: Can I bind an array to an IN() condition?

我的代码最终如此:

$file_handle = fopen("D:/Apapub/public_html/databases/B13/temp/grabevents.txt", "r");

while (!feof($file_handle) ) {

$text_file = fgetcsv($file_handle);

foreach($text_file as &$val)
$val=$db->quote($val);

$data = implode(',',$text_file);

$q = $db->prepare('Insert Into "public"."tblSedimentGrabEvent" Values ('.$data.')');

$q->execute();
}

现在它可以完美地工作,同时希望防止SQL注入。