所以我将这个CI项目从数据库(包含大量数据)转换为CSV。
我点击"转换为CSV"后,我尝试导出所有数据,加载需要花费很多时间,浏览器会给我一个超时错误。
以下是导出功能的代码:
ini_set('memory_limit', '-1');
set_time_limit(-1);
$prefKey = $this->session->flashdata('prefKey');
$searchKey = $this->session->flashdata('searchKey');
$withEmail = $this->session->flashdata('withEmail');
$list = $this->user_model->get_users($prefKey, $searchKey, $withEmail, "", "");
$headerArray = array("id", "prefecture_id", "industry_id", "offset", "name", "email");
// Header
$header = str_replace(",", "", $headerArray);
$datas = implode(',', $header) . "\r\n";
// Body
foreach($list as $body)
{
$orig_email = $body['email'];
$mstring = preg_replace("/^([^a-zA-Z0-9])*/",',',$orig_email);
preg_match_all("/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i", $mstring, $matches);
$email = implode($matches[0]);
$datas .= $body["id"].",".$body["prefecture_id"].",".$body["industry_id"].",".$body["offset"].",".preg_replace('/[,]/',' ',$body["name"]).",".$email."\r\n";
}
$datas = mb_convert_encoding($datas, "SJIS-win", "UTF-8");
$csvFileName = "phpList_" . date('Ymd_His') . ".csv";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $csvFileName);
header('Content-Transfer-Encoding: binary');
while (ob_get_level() > 0)
{
ob_end_clean();
}
ob_start();
print trim($datas);
ob_flush();
ob_end_clean();
exit;
php.ini的设置如下:
max_execution_time = 259200
max_input_time = 259200
memory_limit = 2G
仍然是同样的错误。
我无法确定停止/超时的位置。是在查询数据时吗?将数据放入CSV?还是正在下载?
从上面提供的代码中,我如何处理批量处理过程?我认为这只是一次性过程。
这是模特:
public function get_users($prefecture_id, $industry_id, $filter, $limit, $start){
$this->db->select('*');
$this->db->from('company');
if ($filter) {
$this->db->like('email','@');
}
if (!empty($prefecture_id) && $prefecture_id != 99) {
$this->db->where('prefecture_id', $prefecture_id);
}
if (!empty($industry_id) && $industry_id != 99) {
$this->db->where('industry_id', $industry_id);
}
if (!empty($limit)) {
$this->db->limit($limit, $start);
}
$this->db->order_by('prefecture_id, industry_id, offset');
$query = $this->db->get();
$result = $query->result_array();
return $result;
}
答案 0 :(得分:1)
超过200万行 - 您必须确保大多数数据不在内存中。
这里你要做的是使用unbuffered_row()
函数
您可以在无缓冲行部分here
下的文档中找到此功能
public function createCSVExportFromCompanyTable($prefecture_id, $industry_id, $filter, $limit, $start)
{
set_time_limit(0);
$this->db->select('*');
$this->db->from('company');
if ($filter) {
$this->db->like('email','@');
}
if (!empty($prefecture_id) && $prefecture_id != 99) {
$this->db->where('prefecture_id', $prefecture_id);
}
if (!empty($industry_id) && $industry_id != 99) {
$this->db->where('industry_id', $industry_id);
}
if (!empty($limit)) {
$this->db->limit($limit, $start);
}
$this->db->order_by('prefecture_id, industry_id, offset');
$query = $this->db->get();
$delimiter = ",";
//$f = fopen('php://memory', 'w');
$f = fopen('exportCompanyData.csv', 'w');
$headerArray = array("id", "prefecture_id", "industry_id", "offset", "name", "email");
fputcsv($f, $headerArray,$delimiter);
while($row = $query->unbuffered_row())
{
$orig_email = $row->email;
$mstring = preg_replace("/^([^a-zA-Z0-9])*/",',',$orig_email);
preg_match_all("/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i", $mstring, $matches);
$email = implode($matches[0]);
$arrLine = [
$row->id, $row->prefecture_id, $row->industry_id, $row->offset, preg_replace('/[,]/',' ',$row->name),$email
];
fputcsv($f, $arrLine, $delimiter);
}
fseek($f, 0);
$csvFileName = "phpList_" . date('Ymd_His') . ".csv";
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="'.$csvFileName.'";');
fpassthru($f);
}
此处唯一的问题可能是$f = fopen('php://memory', 'w');
行
由于记忆问题;
如果您仍然遇到内存问题,请尝试$f = fopen('exportCompanyData.csv', 'w');
代替。
最后一个提示:@First尝试以最多1k行运行此函数 为了确保功能正常。
请注意 - 我只是编写了这段代码 - 所以我不确定一切语法是否正确 - 但路径应该清晰,你应该能够使用这段代码;)
答案 1 :(得分:1)
您应该使用cron作业执行此操作。创建一个每分钟运行的cron作业(https://askubuntu.com/questions/2368/how-do-i-set-up-a-cron-job)。 cronjobs没有超时。
我建议以下功能:
当您按下"生成CSV"按钮你可以在数据库中设置一个标志为" true"并且cron作业将开始创建CSV。靠近"生成CSV"按钮,你可以创建一个隐藏的"下载CSV"按钮(最初将隐藏)。完成此过程后,您可以设置"下载CSV"是可见的(您可以使用来自javascript的ajax调用来检查并查找生成的csv进程是否已完成)。 cron作业将创建/保存CSV到预定义的位置,因此下载按钮将链接(可以是" a href")到csv位置。
如果你正在使用cron作业,请确保你有一个数据库标志,例如" is_running"当生成进程正在运行时,此标志设置为true(tinyint = 1),因此不会启动其他生成csv进程。当进程结束时,将标志设置为false(tinyint = 1)。
其他选项是让服务器每隔60/30分钟调用一次这个cron作业,并从一开始就显示下载按钮。每次运行cron都会更新(删除/创建)相同的csv文件。
答案 2 :(得分:0)
尝试插入大数据的示例并增加php超时限制:
$data = array(
array( 'item' => 'Server', 'cost' => 10000, 'approved by' => 'Joe'),
array( 'item' => 'Mt Dew', 'cost' => 1.25, 'approved by' => 'John'),
array( 'item' => 'IntelliJ IDEA', 'cost' => 500, 'approved by' => 'James')
);
$fp = fopen('file.csv', 'w');
$i = 0;
foreach ($data as $fields) {
if($i == 0){
fputcsv($fp, array_keys($fields), 4800);// the number defines the buffer /bytes to be inserted at a time.
}
fputcsv($fp, array_values($fields));
$i++;
}
fclose($fp);
并更新.htaccess:
<IfModule mod_rewrite.c>
php_value memory_limit 256M
</IfModule>