Я сделал этот скрипт, где я запускаю WP_Query (), который получает около 2000 записей и растет. Я хочу иметь возможность записать эти результаты в файл 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 или что-то в этом роде.
Вот последний, неотредактированный сценарий. Имейте в виду, что используемый в MySQL запрос использует диапазон дат и 3 метаданных для получения подмножества данных из нашей базы данных. Я получаю около 1290 результатов, все записано в файл CSV. (Спасибо Дэвиду за помощь.)
$path = $_SERVER['DOCUMENT_ROOT'];
include_once $path . '/wp-load.php';
// SET UP DB VARS
$host = DB_HOST;
$user = DB_USER;
$pass = DB_PASSWORD;
$db = DB_NAME;// CONNECT TO DB
$link = mysql_connect($host, $user, $pass) or die("Can not connect." . mysql_error());
mysql_select_db($db) or die("Can not connect.");
$mycolums = array( 'Email,Photo1,Photo2,Photo3,VideoURL' );
foreach ( $mycolums as $column ) {
$csv_output = $column.", ";
}
$csv_output .= "\n";
$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,9999");
while ($rowr = mysql_fetch_row($values)) {
$postID = $rowr[0];
$user_email = get_post_meta($postID, 'email_address', true);
$photo1 = get_post_meta($postID, 'photo_1', true);
$photo2 = get_post_meta($postID, 'photo_2', true);
$photo3 = get_post_meta($postID, 'photo_3', true);
$videourl = get_post_meta($postID, 'the_video', true);
// $csv_output .= $rowr['']."; ";
$csv_output .= $user_email.', '.$photo1.', '.$photo2.', '.$photo3.', '.$videourl.',';
$csv_output .= "\n";
}
$output_filename = "export_".date("Y-m-d_H-i",time()).".csv";
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d_H-i",time()) . ".csv");
header( "Content-disposition: filename=".$output_filename);
print_r($csv_output);
exit;
Я надеюсь, что это помогает кому-то еще, кто имеет дело с проблемами памяти.
Я также получал «Пытался выделить больше фатальной ошибки памяти», но мое решение заключалось в том, что внутри цикла while я пропустил эту строку:
$wp_query->the_post();
Может быть полезно, если кто-то еще сталкивается с той же проблемой.