php从csv获取数据并再次将它们写入相同的csv

时间:2016-09-30 09:56:46

标签: php mysql csv fputcsv

我有像这样的csv

product_id,stock_unit
1, ,
2, ,
3, ,
4, ,
5, ,
6, ,

现在在我的PHP代码中,我将获得产品ID并对数据库运行查询以从数据库中获取库存单元。获取产品的库存单元后,脚本应将其更新为csv而不更改任何名称。

所以我所有的代码都是这样的

<?php
$mysqli = new mysqli("localhost", "username", "password", "database");

/* check connection */
if ($mysqli->connect_errno) {
    printf("Connect failed: %s\n", $mysqli->connect_error);
    exit();
}

$file = "update_pd.csv";
$csv = array_map("str_getcsv", file($file,FILE_SKIP_EMPTY_LINES));
$keys = array_shift($csv);

$stock_array = array();
if (($handle = fopen($file, "r")) !== FALSE) {
    fgetcsv($handle);
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        $stock_array[] = get_data($data[0]);
    }
    fclose($handle);
}
//print_r($stock_array);
$handle = fopen("update_pd.csv", "a");
fputcsv($handle, $stock_array);


function get_data($id) {
    if( !empty($id) ) {
        $result = $mysqli->query("SELECT `stock_unit` FROM `products` WHERE `product_id` = ".$id." ");
        if( $result ) {
            while($row = $result->fetch_assoc()) {
                return $row['stock_unit'];
            }
        }
    }
}

这里写的是csv我的意思是数据写在最后一行,所有旧的数据都存在。脚本应根据csv文件中的产品ID写入库存数量,而不对csv头和文件名进行任何更改。有人能告诉我怎么做吗?任何帮助和建议都会非常明显。

更新

由于库存单位将从数据库中获取。输出应该像

product_id,stock_unit
1, 24,
2, 22,
3, 37,
4, 46,
5, 89,
6, 96,

1 个答案:

答案 0 :(得分:0)

如果我找到你,你的代码正在运行,但会附加数据而不是覆盖文件。这是因为你在做:

$handle = fopen("update_pd.csv", "a");

将以追加模式打开文件。要覆盖它,您需要在写入模式下打开它,例如

$handle = fopen("update_pd.csv", "w");

请参阅PHP Manual for fopen

mode参数的说明
  

'w' - 仅供写作;将文件指针放在文件的开头,并将文件截断为零长度。如果该文件不存在,请尝试创建它。

     

'a' - 仅供写作;将文件指针放在文件的末尾。如果该文件不存在,请尝试创建它。在这种模式下,fseek()无效,写入总是附加。

但是,您在$mysqli函数中使用get_data变量,但该变量未在该范围内定义,因此它根本不起作用。确保将变量传递给函数,例如

function get_data($mysqli, $id) {

然后像这样调用它:

get_data($mysqli, $data[0]);

但是如果你的查询基本相同并且只在WHERE子句中使用不同的值,那么使用Prepared Statements可以更快地执行查询。

在创建mysqli实例后在全局范围内定义:

$query = $mysqli->prepare(
    "SELECT `stock_unit` FROM `products` WHERE `product_id` = ?
);

然后,不是将$mysqli变量传递给get_data,而是传递$query变量。将get_data函数更改为此代码:

function get_data($query, $id) {
    if( !empty($id) ) {
        $query->bind_param("i", $id);
        $result = $query->execute($query);
        …

作为替代方案,不要单独提取股票单位,而应考虑:

$file = "file.csv";
$data = array_map('str_getcsv', file($file, FILE_SKIP_EMPTY_LINES));
$ids = array_filter(array_column($data, 0), 'is_numeric');
$ids = implode(',', $ids);

然后使用WHERE … ININTO OUTFILE在一个查询中完成所有操作:

SELECT "product_id", "stock_unit"
UNION ALL
SELECT product_id, stock_unit
FROM products
WHERE product_id IN ($ids)
INTO OUTFILE '/path/to/update_pd.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY ',\n';

请注意,由于SQL注入攻击的风险,将变量插入查询是不好的做法。但是既然我们确保id是数字的,那么在这种情况下它是可以的。另外,mysqli does not allow easy binding of values in WHERE … IN queries