如何在php中上传和解析CSV文件

Posted

技术标签:

【中文标题】如何在php中上传和解析CSV文件【英文标题】:How to upload and parse a CSV file in php 【发布时间】:2011-08-01 09:32:00 【问题描述】:

我想用 php 上传一个 csv 文件。文件上传后,我想显示CSV文件的数据。我想要一个如何完成此任务的示例。

【问题讨论】:

Handling file uploads 在 PHP 手册中 fgetcsv() 在 PHP 手册中 您没有找到任何解释使用 PHP 上传文件的教程?我敢打赌有一些...... 我在选择插件时感到困惑,建议我最好的插件来上传 php 文件。 复制parse csv file php,Quick php file upload guide 【参考方案1】:

您需要 PHP 手册中的处理文件上传部分,并且还可以查看 fgetcsv() 和 explode()。

【讨论】:

注意字符串值中的逗号、引号和换行符,您应该使用状态机来拆分 CSV,而不是爆炸。【参考方案2】:

我觉得str_getcsv — 将 CSV 字符串解析为数组是您的最佳选择。

    您需要将文件上传到服务器。

    使用 str_getcsv 解析文件。

    遍历数组并根据您网站上的需要对齐。

【讨论】:

感谢您的回复。我还有一个问题要问您,哪个是上传文件的最佳插件,可以避免代码大小并具有良好的用户界面,请给我推荐一个插件 @vinay - 我更喜欢自己编写上传脚本。上传插件是什么意思???你可以自己写一个……最多 10 行代码 @vinay - 如果你真的想做一个插件(php +js),请查看tinyurl.com/44nv6yt【参考方案3】:

虽然您可以轻松找到如何使用 php 处理文件上传的教程,并且有处理 CSV 的函数(手动),但我将发布一些代码,因为就在几天前,我还在做一个项目,包括一些您可以使用的代码...

html

<table >
<form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="post" enctype="multipart/form-data">

<tr>
<td >Select file</td>
<td ><input type="file" name="file" id="file" /></td>
</tr>

<tr>
<td>Submit</td>
<td><input type="submit" name="submit" /></td>
</tr>

</form>
</table>

PHP:

if ( isset($_POST["submit"]) ) 

   if ( isset($_FILES["file"])) 

            //if there was an error uploading the file
        if ($_FILES["file"]["error"] > 0) 
            echo "Return Code: " . $_FILES["file"]["error"] . "<br />";

        
        else 
                 //Print file details
             echo "Upload: " . $_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 />";

                 //if file already exists
             if (file_exists("upload/" . $_FILES["file"]["name"])) 
            echo $_FILES["file"]["name"] . " already exists. ";
             
             else 
                    //Store file in directory "upload" with the name of "uploaded_file.txt"
            $storagename = "uploaded_file.txt";
            move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $storagename);
            echo "Stored in: " . "upload/" . $_FILES["file"]["name"] . "<br />";
            
        
      else 
             echo "No file selected <br />";
     

我知道必须有更简单的方法来做到这一点,但我读取了 CSV 文件并将每条记录的单个单元格存储在一个二维数组中。

if ( isset($storagename) && $file = fopen( "upload/" . $storagename , r ) ) 

    echo "File opened.<br />";

    $firstline = fgets ($file, 4096 );
        //Gets the number of fields, in CSV-files the names of the fields are mostly given in the first line
    $num = strlen($firstline) - strlen(str_replace(";", "", $firstline));

        //save the different fields of the firstline in an array called fields
    $fields = array();
    $fields = explode( ";", $firstline, ($num+1) );

    $line = array();
    $i = 0;

        //CSV: one line is one record and the cells/fields are seperated by ";"
        //so $dsatz is an two dimensional array saving the records like this: $dsatz[number of record][number of cell]
    while ( $line[$i] = fgets ($file, 4096) ) 

        $dsatz[$i] = array();
        $dsatz[$i] = explode( ";", $line[$i], ($num+1) );

        $i++;
    

        echo "<table>";
        echo "<tr>";
    for ( $k = 0; $k != ($num+1); $k++ ) 
        echo "<td>" . $fields[$k] . "</td>";
    
        echo "</tr>";

    foreach ($dsatz as $key => $number) 
                //new table row for every record
        echo "<tr>";
        foreach ($number as $k => $content) 
                        //new table cell for every field of the record
            echo "<td>" . $content . "</td>";
        
    

    echo "</table>";

所以我希望这会有所帮助,这只是一小段代码,我没有测试过,因为我使用它略有不同。 cmets应该解释一切。

【讨论】:

如果有人想在文本字段中保存从内部foreach 循环获得的$content 怎么办?我在这里尝试这样做:***.com/questions/14536221/… 下面使用 fgetcsv 的答案看起来更好,因为它应该正确处理转义字符。 是的,我明白了,fgetcsv 可能是更好的选择。 为什么要上传文件,我们可以在不保存服务器的情况下读取文件吗? @Mrworldwide PHP 是一个服务器端程序,因此您必须上传文件或使用 AJAX JS 将数据发送回服务器。您可以在不保存 JS 的情况下阅读(在这种情况下,请查看 Papa Parse),但这个 Q 和明确用于 PHP 解决方案:“......在我上传文件后......”。【参考方案4】:

未经测试,但应该给你的想法。观点:

<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="csv" value="" />
<input type="submit" name="submit" value="Save" /></form>

upload.php 控制器:


$csv = array();

// check there are no errors
if($_FILES['csv']['error'] == 0)
    $name = $_FILES['csv']['name'];
    $ext = strtolower(end(explode('.', $_FILES['csv']['name'])));
    $type = $_FILES['csv']['type'];
    $tmpName = $_FILES['csv']['tmp_name'];

    // check the file is a csv
    if($ext === 'csv')
        if(($handle = fopen($tmpName, 'r')) !== FALSE) 
            // necessary if a large csv file
            set_time_limit(0);

            $row = 0;

            while(($data = fgetcsv($handle, 1000, ',')) !== FALSE) 
                // number of fields in the csv
                $col_count = count($data);

                // get the values from the csv
                $csv[$row]['col1'] = $data[0];
                $csv[$row]['col2'] = $data[1];

                // inc the row
                $row++;
            
            fclose($handle);
        
    

【讨论】:

快速提问解析后文件会被删除吗?它只是临时存储在临时文件夹下,对吗? 一个很好的解决方案,但不知道为什么你只抓取每行的前两列?另外,$csv[$row]['row1'] = $data[0]; 具有误导性,它应该是$csv[$row]['column1'] = $data[0];。无论如何,更好的解决方案是使用$csv[$row]=$data 并用整个文件制作一个多维数组。 最好检查 MIME 而不是文件扩展名。 感谢您的解决方案。我将 $num 编辑为 $col_count 并将 row1, row2 索引编辑为 col1, col2 因为这就是它们的内容,并且这是唯一令人困惑的部分。我通常不会禁用执行时间,而是在 while 循环中设置 set_time_limit(60),因此只要我们正在读取行,它就会保持重置,然后在完成后再次开始倒计时。这样,如果退出循环后还有其他问题,那么它会像预期的那样超时,我们不必担心文件会持续多长时间。 @Bruce 据我了解,它可能会被未来的保存删除或覆盖,但这将是这些交互的副产品。因此,除非您明确声明,否则不要指望它被永久删除或保存。【参考方案5】:
function doParseCSVFile($filesArray)
    
        if ((file_exists($filesArray['frmUpload']['name'])) && (is_readable($filesArray['frmUpload']['name'])))  

            $strFilePath = $filesArray['frmUpload']['tmp_name']; 

            $strFileHandle = fopen($strFilePath,"r");
            $line_of_text = fgetcsv($strFileHandle,1024,",","'"); 
            $line_of_text = fgetcsv($strFileHandle,1024,",","'"); 

            do  
                if ($line_of_text[0])  
                    $strInsertSql = "INSERT INTO tbl_employee(employee_name, employee_code, employee_email, employee_designation, employee_number)VALUES('".addslashes($line_of_text[0])."', '".$line_of_text[1]."', '".addslashes($line_of_text[2])."', '".$line_of_text[3]."', '".$line_of_text[4]."')";
                    ExecuteQry($strInsertSql);
                               
             while (($line_of_text = fgetcsv($strFileHandle,1024,",","'"))!== FALSE);

         else 
            return FALSE;
        
    

【讨论】:

【参考方案6】:

现在可以以更简单的方式完成。

$tmpName = $_FILES['csv']['tmp_name'];
$csvAsArray = array_map('str_getcsv', file($tmpName));

这将返回一个已解析的 CSV 数据数组。然后你可以使用 foreach 语句循环遍历它。

【讨论】:

除了这个出色的解决方案之外,使用explode(&lt;delimiter&gt;, $csv) 您还可以分隔每个字段,并在 CSV 数组的每个元素中包含一个字段数组。 $csvAsArray = array_map('str_getcsv', file($_FILES['csv']['tmp_name']));如果您需要它更简单。 虽然这看起来既快捷又简单,但这并不是一个完整或安全的解决方案。它至少应该涉及 move_uploaded_file() 以确保文件实际上是通过 $_POST 上传的;其次,没有检查这是否是 CSV 文件。尝试上传一些图形,看看 $csvAsArray 里面有什么......! 非常出色的答案。 我有一个问题。如果我使用通常的 fopen 打开,我的文本是这样的 ["19","This is a \nlonger\nscrolling name","NULL"]。如果我使用上面的方法,它变成了 ["19","This is a \n"],["longer"],["scrolling name\"","NULL"]。其他人有类似的问题吗?【参考方案7】:

你可以试试这个:

function doParseCSVFile($filesArray)

    if ((file_exists($filesArray['frmUpload']['name'])) && (is_readable($filesArray['frmUpload']['name'])))  

        $strFilePath = $filesArray['frmUpload']['tmp_name']; 

        $strFileHandle = fopen($strFilePath,"r");
        $line_of_text = fgetcsv($strFileHandle,1024,",","'"); 
        $line_of_text = fgetcsv($strFileHandle,1024,",","'"); 

        do  
            if ($line_of_text[0])  
                $strInsertSql = "INSERT INTO tbl_employee(employee_name, employee_code, employee_email, employee_designation, employee_number)VALUES('".addslashes($line_of_text[0])."', '".$line_of_text[1]."', '".addslashes($line_of_text[2])."', '".$line_of_text[3]."', '".$line_of_text[4]."')";
                ExecuteQry($strInsertSql);
                           
         while (($line_of_text = fgetcsv($strFileHandle,1024,",","'"))!== FALSE);

     else 
        return FALSE;
    

【讨论】:

答案不完全相关,复制/粘贴类型的东西。他在这里使用数据库和东西。【参考方案8】:

我在@Thomas Clowes 回答的帮助下在 sn-p 下面创建了

$tmpName = $_FILES['csv']['tmp_name'];

$csv_data = array_map('str_getcsv', file($tmpName));

array_walk($csv_data , function(&$x) use ($csv_data) 
  $x = array_combine($csv_data[0], $x);
);

/** 
*
* array_shift = remove first value of array 
* in csv file header was the first value
* 
*/
array_shift($csv_data);

// Print Result Data
echo '<pre/>';
print_r($csv_data);    

会得到如下结果

 Array
(
   [0] => Array
    (
        
        [make] => Audi
        [model] => S4
        [grade] => 
        [chassis] => WAUZZZ8K9DA076529
        [year] => 2012
        [kms] => 127000
        [color] => White
        [doors] => 4
        [cc] => 3000
        [engineno] => 
        [trans] => FAT
        [fueltype] => P
        [condition] => 4            
        [price] => 15753
        
    )

)

【讨论】:

【参考方案9】:
public function uploadCsvFile()
   try 
    if($_SERVER['REQUEST_METHOD'] === 'POST')
        $request = $this->post();
        $fileName = $request->file;
        $file = fopen($fileName, "r"); //open the file
        // $fileName = $_FILES["file"]["tmp_name"];
        while(($column = fgetcsv($file)) !== FALSE)
            $num = count($column);
            $this->dbw->query("insert into csv_upload(first_name,last_name,email,phone,address,pin) values('".$column[0]."','".$column[1]."','".$column[2]."','".$column[3]."','".$column[4]."','".$column[5]."')");
        

        fclose($file);
    
    catch (Exception $e) 
        $this->responseErr($e->getMessage(), 500);
    

【讨论】:

请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。

以上是关于如何在php中上传和解析CSV文件的主要内容,如果未能解决你的问题,请参考以下文章

如何上传csv文件并解析它?

如何在 PHP 中解析 CSV 文件

php解析csv文件

如何检测上传的csv文件的编码

使用 D3.js 解析上传的 CSV 文件

如何使用 PHP 解析 CSV 文件 [重复]