<?php
// $Revision: 1.15.2.1.2.15 $
// ------------------------------------------------------------------------- //
//  XooNIps - Neuroinformatics Base Platform System                          //
//  Copyright (C) 2005-2008 RIKEN, Japan All rights reserved.                //
//  http://xoonips.sourceforge.jp/                                           //
// ------------------------------------------------------------------------- //
//  This program is free software; you can redistribute it and/or modify     //
//  it under the terms of the GNU General Public License as published by     //
//  the Free Software Foundation; either version 2 of the License, or        //
//  (at your option) any later version.                                      //
//                                                                           //
//  You may not change or alter any portion of this comment or credits       //
//  of supporting developers from this source code or any supporting         //
//  source code which is considered copyrighted (c) material of the          //
//  original comment or credit authors.                                      //
//                                                                           //
//  This program is distributed in the hope that it will be useful,          //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of           //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
//  GNU General Public License for more details.                             //
//                                                                           //
//  You should have received a copy of the GNU General Public License        //
//  along with this program; if not, write to the Free Software              //
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA //
// ------------------------------------------------------------------------- //

/* Downloads attached file with or without compress option
 * 
 * input:
 *    $_GET['file_id'] or $_POST['file_id']
 *    one-time-token 'xoonips_download_token'
 * 
 * 1. Temporary file in the download procedure will be made in /tmp.
 * 2. Temporary file and directory will be removed after the download completion.
 * bug: /tmp file will be retain when the httpd terminated abnormally.
 * 
 */

session_cache_limiter('none'); // avoid IE bug1 -> http://jp2.php.net/header  Harry 10-Dec-2004 03:26

include 'include/common.inc.php';
require_once 'include/lib.php';
require_once 'include/AL.php';

function error($message){
	header("HTTP/1.0 500 Internal Server Error");
	echo "error:" . $message;
	exit;
}

function error403(){
	header("HTTP/1.0 403 Forbidden");
	echo "403 Forbidden";
	exit;
}

function error404(){
	header("HTTP/1.0 404 Not Found");
	echo "404 Not Found";
	exit;
}

$xnpsid = $_SESSION['XNPSID'];
if (is_object($xoopsUser))
	$uid = $xoopsUser->getVar('uid');
else
	$uid = UID_GUEST;

// Add start NTTDK and Keio University 20080825
$doi_column_name = XNP_CONFIG_DOI_FIELD_PARAM_NAME;
$doi = '';
$order_sql = ' ORDER BY tf.file_id ';
$file_types = explode( ',', XNP_CONFIG_DOWNLOAD_FILE_TYPE_LIMIT );
$file_types_sql = '';
foreach ( $file_types as $value ) {
  if( strlen( $file_types_sql ) > 0 ) {
    $file_types_sql .= ',';
  }
  if( strlen( $value ) > 0 ) {
    $file_types_sql .= '\'' . $value . '\'';
  }
}
if( strlen( $file_types_sql ) > 0 ) {
  $file_types_sql = ' AND tf.mime_type IN (' . $file_types_sql . ') ';
}
$sql_limit = '';
$separate_param = XNP_CONFIG_DOWNLOAD_DOI_FIELD_SEPARATE_PARAM;
// Add end NTTDK and Keio University 20080825

// -> fileID
$formdata =& xoonips_getutility( 'formdata' );
$fileID = $formdata->getValue( 'both', 'file_id', 'i', false );
if ( is_null( $fileID ) ) {
  // Mod start NTTDK and Keio University 20080825
  // error404();
  $doi = $formdata->getValue( 'both', $doi_column_name, 's', false );
  if ( ! is_null( $doi ) ) {
    if ( preg_match( '/'.preg_quote( $separate_param, '/').'/', $doi ) ) {
      $tmp = explode( $separate_param, $doi, 2 );
      $doi = $tmp[0];
      if ( preg_match( '/[1-9]/', intval( $tmp[1] ) ) ) {
        $no = intval($tmp[1]) - 1;
        $no_limit = $no + 1;
        $sql_limit = ' LIMIT '.$no.','.$no_limit;
      }
    } else {
      $sql_limit = '';
    }
  } else {
    error404();
  }
  // Mod end NTTDK and Keio University 20080825
}

// fileID -> itemID, mid, etc.
$itemTable = $xoopsDB->prefix('xoonips_item_basic');
$itemTypeTable = $xoopsDB->prefix('xoonips_item_type');
$fileTable = $xoopsDB->prefix('xoonips_file');
$fileTypeTable = $xoopsDB->prefix('xoonips_file_type');
$moduleTable = $xoopsDB->prefix('modules');
if ( isset( $fileID ) ) {
  $sql = "select tf.item_id, tf.file_id, tf.original_file_name, tf.mime_type, tit.item_type_id, tit.name, tit.display_name, tft.name ".
    " from $fileTable as tf ".
    " left join $fileTypeTable as tft on tf.file_type_id=tft.file_type_id ".
    " left join $moduleTable as tm on tft.mid=tm.mid ".
    " left join $itemTable as ti on ti.item_id=tf.item_id ".
    " left join $itemTypeTable as tit on tit.item_type_id=ti.item_type_id " .
    " where file_id=${fileID} and is_deleted=0";
} else if ( isset( $doi ) ) {
  $sql = "select tf.item_id, tf.file_id, tf.original_file_name, tf.mime_type, tit.item_type_id, tit.name, tit.display_name, tft.name ".
    " from $fileTable as tf ".
    " left join $fileTypeTable as tft on tf.file_type_id=tft.file_type_id ".
    " left join $moduleTable as tm on tft.mid=tm.mid ".
    " left join $itemTable as ti on ti.item_id=tf.item_id ".
    " left join $itemTypeTable as tit on tit.item_type_id=ti.item_type_id ".
    " where ti.doi='${doi}' ".$file_types_sql." and is_deleted=0".$order_sql.$sql_limit;
}
$result = $xoopsDB->query($sql);
if ($result == false || $xoopsDB->getRowsNum($result) == 0){
	error404();
}
list($item_id, $fileID, $originalFileName, $mimeType, $item_type_id, $name, $item_type_display_name, $fileTypeName ) = $xoopsDB->fetchRow($result);

$itemtypes = array();
$result = xnp_get_item_types( $itemtypes );
if ( $result != RES_OK )
	error(_MD_XOONIPS_ITEM_BAD_FILE_TYPE);
foreach ( $itemtypes as $itemtype ){
	if ( $itemtype['item_type_id'] == $item_type_id )
		break;
}
// include view.php
if ("" != $item_type_id){
	include_once XOOPS_ROOT_PATH . '/modules/' . $itemtype['viewphp'];
}
else {
	error(_MD_XOONIPS_ITEM_BAD_FILE_TYPE);
}

// Check the access rights.
$item = array();
if (0 != xnp_get_item($xnpsid,$item_id,$item)){
	error403();
}

// Remove the temporary files at the end of this function. 
function onShutdown(){
	global $removeFiles;
	global $removeDir;
	global $lockFile;
	foreach ($removeFiles as $file)
		unlink($file);
	if ($removeDir) rmdir($removeDir);
	if ($lockFile) unlink($lockFile); // delete last.
}

// Check the download limitations. 
include_once XOOPS_ROOT_PATH . '/modules/' . $itemtype['viewphp'];
$fname_dllimit = "${name}GetAttachmentDownloadLimitOption";
if( function_exists( $fname_dllimit ) && $fname_dllimit( $item_id ) == 1 ){
	// If not a user, redirect to user.php
	// Log in first to download
	if ($uid==UID_GUEST){
		$parsed = parse_url(XOOPS_URL);
        header( "Location:".XOOPS_URL.'/modules/xoonips/user.php?xoops_redirect='.urlencode( $parsed['path']."/modules/xoonips/detail.php?item_id=${item_id}&op=download&download_file_id=${fileID}" ) );
		exit();
    }
}

$fname = "${name}GetDownloadConfirmationRequired";
if ( function_exists( $fname ) && $fname( $item_id ) ){
  // let users confirm(reconfirm) and download
  include 'class/base/gtickets.php';
  $ticket_area = 'xoonips_download_token'.$fileID;
  if ( ! $xoopsGTicket->check( true, $ticket_area, false ) ) {
    $redirect_url = 'detail.php?item_id='.$item_id.'&op=download&download_file_id='.$fileID;
    if ( isset( $_POST['XOOPS_G_TICKET'] ) ) {
      // bad token ticket, maybe this ticket already used
      redirect_header( $redirect_url, 5, _MD_XOONIPS_ITEM_ATTACHMENT_BAD_TOKEN_LABEL );
    } else {
      // no token ticket found
      header( 'Location:'.$redirect_url );
    }
    exit();
  }
}

$fname = "${name}GetAttachmentDownloadNotifyOption";
$private_message = false;

if ( function_exists( $fname ) && $fname( $item_id ) ){
	if ( $_SERVER['REQUEST_METHOD'] == 'GET' ){
		// to send private message(update DB), method must be POST.
		header( "Location:".XOOPS_URL."/modules/xoonips/detail.php?item_id=${item_id}&op=download&download_file_id=${fileID}" );
		exit();
	}
	// notification later
	$private_message = true;
}


$lockFile = "";
$removeDirs  = array(); // Directories to remove at the end of the procedures.
$removeFiles = array(); // Files       to remove at the end of the procedures.

register_shutdown_function('onShutdown');

// convert original_file_name. server_charset+numeric -> utf8
$unicode =& xoonips_getutility( 'unicode' );
$utf8OriginalFileName = mb_decode_numericentity( 
  $unicode->encode_utf8($originalFileName,xoonips_get_server_charset()),
  xoonips_get_conversion_map(), 'UTF-8' );

// Get the download option ON:COMPRESS with METADATA, OFF:UNCOMPRESS
$result = xnp_get_config_value( 'download_file_compression', $download_val);
if ( $result != RES_OK ) error(_MD_XOONIPS_DOWNLOAD_ABNORMAL_CONFIGURATION);

if ($download_val == 'on'){
  $DownloadFileName = "${item_type_display_name}_${fileID}.zip";
}
else {
  $DownloadFileName = $utf8OriginalFileName;
}

$download =& xoonips_getutility( 'download' );

// TODO: don't rely on mb_detect_encoding... 
if ( ! $download->check_pathinfo( $DownloadFileName ) ) {
  $url = XOOPS_URL . '/modules/xoonips/download.php?file_id='.$fileID;
  $url = $download->append_pathinfo( $url, $DownloadFileName );
  // append_pathinfo() + status code 307 + redirection don't work because 
  // Safari ignores 307. 
  header( 'Location: '.$url );
  exit();
}

$client_filename = $download->convert_to_client( $DownloadFileName, 'u' );
$attachmentFileName4zip = $download->convert_to_client( $utf8OriginalFileName, 'u' );

// Bring the attachment file to the working (temporary) directory.
//
// todo: There is a possibility that originalFileName contains illegal charecters.
//       It is necessary to remove these codes.
//       Currently these codes are just avoided by using "urlencode".
//       More effective sanitizing ways should be incorporated.
//
if ( strstr($utf8OriginalFileName, '..') ){
  error(_MD_XOONIPS_ITEM_BAD_FILE);
}

if ($download_val == 'on'){
// Download Zipped file mode
  
  // Prepare the working directory at /tmp/ for generating ZIP
  $removeFiles[] = $lockFile = tempnam('/tmp/', 'XooNIpsDownload');
  if (false === $lockFile){
    error(_MD_XOONIPS_ITEM_CANNOT_CREATE_TMPFILE);
  }
  $removeDir = $baseDir = $lockFile . 'D';
  if (false === mkdir($baseDir)){
    error(_MD_XOONIPS_ITEM_CANNOT_CREATE_TMPFILE);
  }
  chdir($baseDir);
  
  // Generate temporary filename in /tmp from the sanitized file name.
  $rawFiles = array(); // Files will be zipped.
  $removeFiles[] = $baseDir . '/' . $attachmentFileName4zip;
  $rawFiles[] = $attachmentFileName4zip;
  if( !function_exists('symlink') || false === symlink(xnpGetUploadFilePath($fileID), $attachmentFileName4zip) ){
      if( false == copy(xnpGetUploadFilePath($fileID), $attachmentFileName4zip) ){
          error( _MD_XOONIPS_ITEM_CANNOT_CREATE_TMPFILE );
      }
  }

  // Generate attached metadata.
  $fname = "${name}GetMetaInformation";
  $meta = $fname($item_id); //return arary('title' => 'title char lists',...)
  $removeFiles[] = $baseDir . '/metainfo.txt';
  $rawFiles[] = 'metainfo.txt';
  $h = fopen($baseDir.'/metainfo.txt', "w");
  if (false === $h){
    error(_MD_XOONIPS_ITEM_CANNOT_CREATE_TMPFILE);
  }
  $wk = "";
  foreach ($meta as $key=>$val){
  	$wk .= $key;
  	$val = str_replace("\r","\n",str_replace("\r\n", "\n", $val));
  	$ar = explode("\n", $val);
  	if (count($ar) <= 1){
  		$wk .= ": ";
  		$wk .= $val;
  		$wk .= "\r\n";
  	}
  	else {
  		$wk .= ": \r\n  ";
  		$wk .= implode("\r\n  ", $ar);
  		$wk .= "\r\n";
  	}
  }
  $wk .= _MD_XOONIPS_ITEM_DETAIL_URL.": ". xnpGetItemDetailURL( $item_id ) ."\r\n";
  $wk = $unicode->encode_utf8($wk);
  fwrite($h, $wk);
  fclose($h);

  // Generate ZIP
  $removeFiles[] = $DownloadFile = $baseDir . '/zip.zip';
  $zip =& xoonips_getutility( 'zip' );
  $zip->open( $DownloadFile );
  foreach ( $rawFiles as $fname ) {
    $zip->add( $baseDir.'/'.$fname, $fname );
  }
  $result = $zip->close();
  if ( ! $result ) {
    error(_MD_XOONIPS_ITEM_CANNOT_CREATE_ZIP);
  }
}else if ($download_val == 'off'){
  // Download plane file mode (download uncompressed file without metadata)
  $result = xnp_get_config_value( 'upload_dir', $upload_dir_val);
  if ( $result != RES_OK ) error(_MD_XOONIPS_DOWNLOAD_ABNORMAL_CONFIGURATION);
  $DownloadFile     = $upload_dir_val .'/' . $fileID;
}else{
  error(_MD_XOONIPS_DOWNLOAD_ABNORMAL_CONFIGURATION);  
}

// Record download file LOG.
$eventlog_handler =& xoonips_getormhandler( 'xoonips', 'event_log' );
$eventlog_handler->recordDownloadFileEvent( $item_id, $fileID );

$xoopsDB->queryF( "update " . $xoopsDB->prefix('xoonips_file') . " set download_count = download_count+1, timestamp=timestamp where file_id=$fileID" );


$download->download_file( $DownloadFile, $DownloadFileName );

if ( $private_message ){
	xoonips_notification_user_file_downloaded( $fileID, $uid );
}
?>
