Last updated August 31, 2012. Created on August 31, 2012.
Edited by NancyDru. Log in to edit this page.

I recently was tasked with creating a report of how many people signed up for the site by date. The query was simple, but creating the file was a bit of a challenge.

 * User sign up report, output as a CSV.
function mymodule_signups_csv() {
// Prevent Devel from messing us up.
$GLOBALS['devel_shutdown'] = TRUE;
// Set the headers to indicate this is a CSV file.
header('Content-type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename=user_signups.csv');
header('Pragma: no-cache');
header('Expires: 0');

// Create a file.
$output = fopen('php://output', 'w');

// Column names.
fputcsv ($output, array('Date', 'Count'));

$query = "SELECT DATE(FROM_UNIXTIME(created)) AS joined, COUNT(*) AS number FROM {users} "
. "WHERE status = 1 "
. "ORDER BY created DESC ";
$result = db_query($query);

// Loop through the rows.
foreach ($result as $row) {
fputcsv($output, (array) $row);


To get to this code was just a matter of creating a MENU_CALLBACK and adding a link to an existing page.

Note the 3rd line. Devel outputs its stuff after the </html> tag, so Excel saw that as data. That simple statement just turns Devel off for this single page load.

Looking for support? Visit the forums, or join #drupal-support in IRC.


leenyx’s picture

Hi, this looks very helpful but please can you explain how to get to this code? Can you give us an example of the MENU_CALLBACK and the link to the existing page?


Making the Internet a better place.

Jose Blas, UX Consultant

NancyDru’s picture

function mymodule_reporting_permission() {
  return array(
'access mymodule reports' => array(
'title' => t('Access reporting section'),
'description' => t('View reports on mymodule activity.'),

mymodule_reporting_menu() {
$items = array();

$items['mymodule-reporting/signups_csv'] = array(
'page callback' => 'mymodule_reporting_signups_csv',
'access arguments' => array('access mymodule reports'),
'type' => MENU_CALLBACK,

 * Downloadable reports.
function mymodule_reporting_downloads() {
$output = '<div id="mymodule-reporting">';
$output .= '<div id="mymodule-reporting-downloads"><br />';
$links = array();

// Add a link to download sign up stats.
$links['signup-download'] = array(
'title' => t('Download registration statistics'),
'href' => 'mymodule-reporting/signups_csv',

$output .= theme('links', array('links' => $links));

$output .= '</div>  <!-- /mymodule-reporting-downloads -->';
$output .= '</div>  <!-- /mymodule-reporting -->';

There is, of course, a lot of other stuff missing from our actual implementation.