【发布时间】:2014-12-10 22:47:46
【问题描述】:
我制作了这个脚本,我在其中运行了一个 WP_Query(),它可能会获得 2,000 条记录并且还在增长。我希望能够将这些结果写入 CSV 文件。当 posts_per_page 设置为 300 或更少的记录时,我可以正常工作。
如果我将 posts_per_page 更改为 -1,则会出现此错误:
Fatal error: Allowed memory size of 134217728 bytes exhausted
我想知道是否有一种方法可以一次将 300 条记录发送到 CSV 文件,直到没有更多记录然后触发文件下载?
或者也许将每一行流式传输到 CSV 文件?执行 fopencsv 时管理内存的最佳方法是什么?
这是我现在拥有的:
$export_query = array(
'post_type' => 'videorepot',
'posts_per_page' => -1,
'status' => 'published',
'meta_query' => array(
array(
'key' => 'agree',
'value' => 1,
'compare' => '=',
),
array(
'key' => 'opt-in',
'value' => 1,
'compare' => '=',
),
array(
'key' => 'status',
'value' => 'Video Ready',
'compare' => '=',
),
)
);
// Posts query
$wp_query = new WP_Query( $export_query );
if ( $wp_query->have_posts() ) :
$list = array( 'Email,Photo1,Photo2,Photo3,VideoURL' );
while ( $wp_query->have_posts() ) : $wp_query->the_post();
$postID = get_the_ID();
$user_email = get_post_meta($postID, 'user_email', true);
$photo1 = get_post_meta($postID, 'photo1', true);
$photo2 = get_post_meta($postID, 'photo2', true);
$photo3 = get_post_meta($postID, 'photo3', true);
$videourl = get_post_meta($postID, 'video_file', true);
$list[] = $user_email.','.$photo1.','.$photo2.','.$photo3.','.$videourl;
endwhile;
endif;
// Output file stream
$output_filename = 'export_' . strftime( '%Y-%m-%d' ) . '.csv';
$output_handle = @fopen( $output_filename, 'w' );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Content-Description: File Transfer' );
header( 'Content-type: text/csv' );
header( 'Content-Disposition: attachment; filename=' . $output_filename );
header( 'Expires: 0' );
header( 'Pragma: public' );
foreach ( $list as $line ) {
// Add row to file
fputcsv( $output_handle, explode(',', $line), ',', '"');
}
// Close output file stream
fclose( $output_handle );
// We're done!
exit;
更新 #1 对于一些测试,我删除了将项目写入 CSV 文件的脚本部分,所以我发现它在我的查询中确实有一些东西让它变得疯狂。我的自定义帖子类型中可能有 3000 条记录。为什么这会使我的查询内存不足?
更新 #2
我决定走另一条路,因为我在使用 wp_query 时仍然遇到内存问题。所以,我编写了我的 mySQL 查询——你知道我是从其他示例中将它一起破解的。这个查询运行得非常快,所以我想我的运气会更好。
我有一个与 meta_key/meta_values 相关的新问题。目前,我在查询中使用 SELECT *,但我不想选择所有内容。我只需要数据库中的大约 5 个字段。我想要的其中一些字段是 meta_key/meta_value。有没有办法可以指定这些 meta_keys,这样当我导出表时,我只能得到 5 列的结果?
我的查询现在看起来像这样:
$values = mysql_query("SELECT * FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id) WHERE 1=1
AND ( ( post_date >= '2014-11-03 00:00:00' AND post_date <= '2014-12-31 23:59:59' ) )
AND wp_posts.post_type = 'videorepot'
AND (wp_posts.post_status = 'publish')
AND ( (wp_postmeta.meta_key = 'agree' AND CAST(wp_postmeta.meta_value AS CHAR) = '1')
AND (mt1.meta_key = 'opt-in' AND CAST(mt1.meta_value AS CHAR) = '1')
AND (mt2.meta_key = 'status' AND CAST(mt2.meta_value AS CHAR) = 'Video Ready') )
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0,20");
现在我将限制设置为 20,但我已经将限制设置为 0,9999 进行了测试,它在 phpmyadmin 中运行得非常快。当我没有设置限制时,上面的查询给了我大约 1282 个结果。
更新 #3
我已经发布了我的答案的解决方案。感谢您的帮助,大卫。
【问题讨论】:
-
增加 php 内存...或者添加 post meta 以表示您已下载并将最大结果设置为 200 左右(不包括下载)
-
我不想简单地增加 php 内存。我有兴趣学习在这种情况下管理内存的正确 PHP 技术。不过我会暂时试试这个。另外根据我允许使用 134 MB 内存的错误,我认为这是相当高的。问题是每次单击链接时我都想导出完整的数据库,因此无需将项目设置为正在下载。尽管如此,还是感谢您的评论。
-
true 但您没有 134 mb 可使用...但在循环后取消设置 wp 查询并使用 while 而不是 foreach (foreach 再次创建另一个副本,因此您实际上有 3 个副本在旅途中),然后在循环遍历它时取消设置 $list 数组。
-
好的。我在循环之后添加了 wp_reset_query() 以重置 wp_query。我对使用“while”而不是“foreach”有点困惑,因为我将查询结果加载到数组中,然后使用 foreach 将每个项目添加到 CSV。我可以尝试删除 foreach 并将 fputcsv 移动到“While”循环中。也许这就是你的意思?我确定某处可能有一个 unset($list) 函数,我会查一下。谢谢。
-
foreach 创建数据的副本,而在没有副本的情况下循环数据。实际上,您实际上可以使用 wp while 循环,这可以节省循环两次。希望您不需要在每次迭代时取消设置值,只需在循环结束时重置发布数据。
标签: php wordpress csv memory-management fputcsv