How do I create a 'page' that creates and downloads a file from within a module I have mymodule.php which contains all the logic for my site.

I need to create something like this.

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");

$array = array(
    array("data11", "data12", "data13"),
    array("data21", "data22", "data23"),
    array("data31", "data32", "data23"));
outputCSV($array);

function outputCSV($data) {
    $outstream = fopen("php://output", "w");
    function __outputCSV(&amp;$vals, $key, $filehandler) {
        fputcsv($filehandler, $vals); // add parameters if you want
    }
    array_walk($data, "__outputCSV", $outstream);
    fclose($outstream);
}


Generally I've been adding items to mymodule_menu(), mymodule_theme(), and directing it to a mymodule_mypage() function, and oftentimes a mypage.tpl.php.

This setup doesn't really make sense for what I need to do here, though. 

I need a linke like mysite.com/mypage to generate/download the csv. 

I don't think that headers will work in a mymodule_mypage() function, and the template files are not appropriate because they load headers/footers etc.

I could just create the php files separately and create links to them, but I'm trying to keep things within the module and with tidy URLs.
Don't forget anything you can do with PHP you can do with Drupal, so headers work in exactly the same way. 

Adding a page callback which sets headers and exits the script (with drupal_exit()) is definitely the right way to do this:

function MYMODULE_MENU() {
  $items['mypage'] = array(
    'title' =&gt; 'CSV',
    'access arguments' =&gt; array('access content'),
    'page callback' =&gt; 'MYMODULE_deliver_csv'
  );

  return $items;
}

function MYMODULE_deliver_csv() {
  // Full complement of headers so IE behaves
  header("Cache-Control: public");
  header("Content-Type: application/octet-stream");
  header("Cache-Control: no-store, no-cache, must-revalidate");
  header("Cache-Control: post-check=0, pre-check=0");
  header("Content-Disposition: attachment; filename=\"filename.csv\";" );
  header("Content-Transfer-Encoding: binary");

  // Print your CSV data here

  // Exit the script
  drupal_exit();
}