【问题标题】:Insert CSV line by line Into Postgres using PHP PDO使用 PHP PDO 将 CSV 逐行插入 Postgres
【发布时间】:2013-05-17 22:28:29
【问题描述】:

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

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

数组([0] => 42601 [1] => 7 [2] => 错误:在或附近出现语法错误 ""INSERT INTO "" LINE 1: "INSERT INTO "public"."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 命令,但我的主管希望它逐行解析,以便稍后运行一些检查

!!回答!!

我不知道如何给@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);

再次感谢!

【问题讨论】:

  • 尝试echo查询而不是运行它;如果您可以看到实际的查询字符串,您可能能够更清楚地看到查询中的错误。如果这没有帮助,请尝试将其粘贴到您最喜欢的 DB GUI 中以进行进一步分析。
  • 感谢@Spudley 帮助我看到了错误。我回应了查询,然后将其复制到 PGAdminIII 中并运行它。事实证明,当我使用 heredoc 时,查询周围不需要任何引号。这有效:
  • $query=

标签: php postgresql csv pdo insert-into


【解决方案1】:

将文本替换到 SQL 中容易出错、不安全、难以调试且风格糟糕。使用带有 PDO 或 pg_query_params 的参数化语句。您的“答案”完全不安全,请不要使用它。

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

也见this prior answer

当您使用它时,请考虑使用效率更高的COPY 将 CSV 直接流式传输到 PostgreSQL 中的表中。请参阅pg_copy_from 或较低级别的pg_put_line 函数。

【讨论】:

    【解决方案2】:

    我从这个页面得到了答案: 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 注入。

    【讨论】:

    • 我不明白您为什么不为此使用COPY。它已经过尝试、测试、简单且有效。
    • 这是我最初使用的,但该项目的负责人希望逐行输入数据,以便我可以检查输入的数据。例如,在提交的列中,如果条目等于yes,则该行将不会输入到数据库中。
    • OK,所以你要过滤输入。这是合理的。有时,当我想这样做时,我会做COPY 将整个输入放入暂存的TEMPORARY 表中,然后使用 SQL 将其与最终表合并。这通常更快更简单,但我想这取决于你是否更擅长使用 PHP 或 SQL。
    • 我也不是很擅长,临时表的想法听起来是完成它的好方法。这是我的第一个“大”项目编程,所以这是一次学习经历。感谢您的帮助。
    • 如果COPY 被允许,那么它通常是优越的,但在某些情况下是不允许的。这样的设置在 Web 服务器上很常见,因为 PHP 中的 exec() 调用经常被禁止,即使是这样,也可能不允许对 psql 接口进行身份验证。从安全的角度来看,在 Web 服务器上允许这些东西通常不是最佳实践。因此,可能需要 STDIN 的逐行方法。
    猜你喜欢
    • 2012-12-23
    • 2016-03-27
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    • 2013-01-28
    • 2013-08-20
    相关资源
    最近更新 更多