<?php

/**
 * @file
 * private_download.module file, which produces the primary functionality.
 * Inspired by http://www.drupalcoder.com/story/406-mixing-private-and-public-downloads-in-drupal-6
 * 
 */

/**
 * Implementation of hook_perm().
 */
function private_download_perm() {
  return array('access private download directory');
}

/**
 * Implementation of hook_menu().
 */
function private_download_menu() {
  $items['admin/settings/private_download'] = array(
    'title' => 'Private Download',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('private_download_admin_form', NULL),
    'access arguments' => array('administer site configuration'),
    'description' => 'Manage private download configuration.',
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Implementation of hook_file_download().
 */
function private_download_file_download($filepath) {
  if (strpos($filepath, variable_get('private_download_directory', 'private') .'/') === 0) {
    if (!user_access('access private download directory')) {
      return -1;
    }

    // define default file header attributes
    $header = array(
      'Content-Type: '. file_get_mimetype($filepath),
      'Content-Length: '. filesize(file_create_path($filepath)),
      'Content-Disposition: attachment; filename="'. mime_header_encode(basename($filepath)) .'"'
    );
    // additional user-defined file header attributes (if any)
    return array_merge($header, explode("\n", variable_get('private_download_header', "Content-Transfer-Encoding: binary\nCache-Control: max-age=60, must-revalidate")));
  }
}

/**
 * Private Download admin configuration form.
 */
function private_download_admin_form() {
  if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) {
    $form['private_download_directory'] = array(
      '#type' => 'textfield',
      '#title' => t('private download directory'),
      '#default_value' => variable_get('private_download_directory', 'private'),
      '#required' => TRUE,
      '#description' => t('The directory where the private download files will be stored. Drupal will need to have write access to this directory.'),
    );
    $htaccess = variable_get('private_download_htaccess', "<IfModule mod_rewrite.c>\n  RewriteEngine on\n  RewriteBase ". base_path() ."system/files/private\n  RewriteRule ^(.*)$ $1 [L,R=301]\n</IfModule>");
    $form['private_download_htaccess'] = array(
      '#type' => 'textarea', 
      '#title' => t('htaccess content'),
      '#default_value' => $htaccess,
      '#required' => TRUE,
      '#rows' => 8,
      '#description' => t('Contents of htaccess file in the private download directory. The RewriteBase path must start with the base path ("/" plus the relative directory path from the webroot, if any) followed by "system/" and the !file_system directory name and ending with the private download directory name defined above. Exp. /system/files/private, /drupal/system/files/private', array('!file_system' => l('file system path', 'admin/settings/file-system'))),
    );
    $header = variable_get('private_download_header', "Content-Transfer-Encoding: binary\nCache-Control: max-age=60, must-revalidate");
    $form['private_download_header'] = array(
      '#type' => 'textarea',
      '#title' => t('file headers'),
      '#default_value' => $header,
      '#required' => TRUE,
      '#rows' => 4,
      '#description' => t('Enter a list of header attributes, one entry per line.'),
    );
    $form['#submit'][] = 'private_download_admin_submit_handler';

    return system_settings_form($form);
  }
  else {
    drupal_set_message(t('The !file_system download method is already set to private.', array('!file_system' => l('file system', 'admin/settings/file-system'))), 'error');
    return FALSE;
  }
}

/**
 * Implementation of hook_validate().
 */
function private_download_admin_form_validate($form, &$form_state) {
  $directory = file_directory_path() .'/'. $form_state['values']['private_download_directory'];
  if (file_check_directory($directory, TRUE) == FALSE) {
    form_set_error('private_download_directory', t('The private download directory does not exist and the system was unable to create it. Please check your !file_system settings.', array('!file_system' => l('file system', 'admin/settings/file-system'))));
  }
  $needle = "/system/files/". $form_state['values']['private_download_directory'] ."\r";
  if (!strstr($form_state['values']['private_download_htaccess'], $needle)) {
    form_set_error('private_download_htaccess', t('The RewriteBase path does not equal %path in htaccess content.', array('%path' => '/system/files/'. $form_state['values']['private_download_directory'])));
  }
}

/**
 * Custom submit handler to process custom form data.
 */
function private_download_admin_submit_handler($form, &$form_state) {
  $filename = file_directory_path() .'/'. $form_state['values']['private_download_directory'] .'/.htaccess';
  if (!private_download_write($filename, $form_state['values']['private_download_htaccess'])) {
    // failed to write htaccess file; report to log and return
    watchdog('private_download', t('Unable to write data to file: !filename', array('!filename' => $filename)), 'error');
    return FALSE;
  }
  
  // clear menu cache to recognize private download directory
  cache_clear_all('*', 'cache_menu', TRUE);
  
  drupal_set_message(t('Remember to set private download directory access permissions for permitted roles on the !permissions_url page.', array('!permissions_url' => l('permissions', 'admin/user/permissions'))));
}

/**
 * Write htaccess data to file.
 * 
 * @param string
 * @param string
 * @return boolean
 * 
 */
function private_download_write($filename, $content) {
  // write data to file; create file if not present
  if ($handle = fopen($filename, 'w+b')) {
    if (fwrite($handle, $content)) {
      fclose($handle);
    }
    else {
      return FALSE;
    }
  }
  else {
    return FALSE;       
  }

  return TRUE;
}

/**
 * Read htaccess data from file.
 * 
 * @param string
 * @return string or boolean
 * 
 */
function private_download_read($filename) {
  // get contents of a file into a string
  if (file_exists($filename)) {
    if ($handle = fopen($filename, 'r')) {
      $content = fread($handle, filesize($filename));
      fclose($handle);
      
      return $content;
    }
  }

  return FALSE;
}