<?php

/**
 *		[Discuz!] (C)2001-2099 Comsenz Inc.
 *		This is NOT a freeware, use is subject to license terms
 *
 *		$Id: Disk.php 29353 2012-04-06 03:00:07Z liudongdong $
 */

if(!defined('IN_DISCUZ')) {
	exit('Access Denied');
}

class Cloud_Service_Disk {

	protected $_util;

	protected $_client;

	protected $_baseUrl;

	protected static $_instance;

	public static function getInstance() {
		global $_G;

		if (!(self::$_instance instanceof self)) {
			self::$_instance = new self();
		}

		return self::$_instance;
	}

	public function __construct() {
		global $_G;

		$this->_util = Cloud::loadClass('Service_Util');
		$this->_client = Cloud::loadClass('Service_Client_Disk');
		$this->_baseUrl = $_G['siteurl'] . 'plugin.php?id=qqconnect:disk&';
	}

	public function saveTask($attach, $openid) {
		global $_G;

		if (!$_G['uid']) {
			throw new Cloud_Exception('noLogin', '30001');
		}
		if (!$openid) {
			throw new Cloud_Exception('noOpenid', '30002');
		}
		$verifyCode = md5($openid . $attach['aid'] . $_G['timestamp'] . $_G['uid']);
		$taskData = array(
			'aid' => $attach['aid'],
			'uid' => $_G['uid'],
			'openid' => $openid,
			'filename' => $attach['filename'],
			'verifycode' => $verifyCode,
			'status' => 0,
			'dateline' => $_G['timestamp'],
		);
		$taskId = C::t('#qqconnect#connect_disktask')->insert($taskData, true);

		$downParams = array(
			'taskid' => $taskId,
			'verifycode' => $verifyCode,
		);
		$downloadUrl = $this->_baseUrl . $this->_util->generateSiteSignUrl($downParams);
		$filePath = self::_getFullPath($attach['attachment']);
		if ($attach['filesize'] <= 10000000 && file_exists($filePath)) {
			$md5 = md5_file($filepath);
			$hash = hash_file('sha1', $filepath);
		}
		$cloudData = array(
			'sId' => $_G['setting']['my_siteid'],
			'openid' => $openid,
			'filename' => $attach['filename'],
			'downloadUrl' => $downloadUrl,
			'md5' => $md5,
			'hash' => $hash,
		);
		$this->_client->sendTask($cloudData);
	}

	public function getAttachment() {
		global $_G;

		try {
			$taskData = $this->checkTask();
		} catch (Exception $e) {
			throw new Cloud_Exception($e);
		}
		$task = $taskData['task'];
		$attach = $taskData['attach'];
		$taskId = $task['taskid'];

		C::t('#qqconnect#connect_disktask')->update($taskId, array(
			'status' => 1,
			'downloadtime' => $_G['timestamp'],
		));
		$db = DB::object();
		$db->close();
		ob_end_clean();
		$attach['filename'] = '"'.(strtolower(CHARSET) == 'utf-8' && strexists($_SERVER['HTTP_USER_AGENT'], 'MSIE') ? urlencode($attach['filename']) : $attach['filename']).'"';
		dheader('Content-Type: application/octet-stream');
		dheader('Content-Length: ' . $attach['filesize']);
		dheader('Content-Disposition: attachment; filename='.$attach['filename']);

		self::_checkXSendFile($attach['attachment']);
		if ($attach['remote']) {
			self::_getRemoteFile($attach['attachment']);
		} else {
			self::_getLocalFile($attach['attachment']);
		}
		exit;
	}

	public function checkTask() {
		global $_G;
		$sId = $_G['setting']['my_siteid'];
		$ts = $_GET['ts'];
		$taskId = $_GET['taskid'];
		$verifyCode = $_GET['verifycode'];
		if ($sId != $_GET['s_id']) {
			throw new Cloud_Exception('sIdError', '30004');
		}
		if ($_G['timestamp'] - $ts > 86400) {
			throw new Cloud_Exception('downloadTimeOut', '30005');
		}
		$params = array(
			'taskid' => $taskId,
			'verifycode' => $verifyCode,
			's_id' => $_GET['s_id'],
			's_site_uid' => $_GET['s_site_uid'],
		);
		$sig = $_GET['sig'];
		$sKey = $_G['setting']['my_sitekey'];
		ksort($params);
		$str = $this->_util->httpBuildQuery($params, '', '&');
		if ($sig != md5(sprintf('%s|%s|%s', $str, $sKey, $ts))) {
			throw new Cloud_Exception('sigError', '30003');
		}

		$task = C::t('#qqconnect#connect_disktask')->fetch($taskId);
		if (!$task) {
			throw new Cloud_Exception('noTask', '30006');
		}
		if ($verifyCode != $task['verifycode']) {
			throw new Cloud_Exception('verifyError', '30009');
		}

		$attach = C::t('forum_attachment_n')->fetch('aid:' . $task['aid'], $task['aid']);
		if (!$attach) {
			throw new Cloud_Exception('noAttachment', '30007');
		}
		$return = array(
			'task' => $task,
			'attach' => $attach,
		);

		return $return;
	}

	public function clearDirtyData() {
		return C::t('#qqconnect#connect_disktask')->delete_by_status(1);
	}

	private static function _getFullPath($attachment) {
		global $_G;

		return $_G['setting']['attachdir'] . 'forum/' . $attachment;
	}

	private static function _getLocalFile($file) {
		$filename = self::_getFullPath($file);
		$readmod = getglobal('config/download/readmod');
		$readmod = $readmod > 0 && $readmod < 5 ? $readmod : 2;
		if($readmod == 1 || $readmod == 3 || $readmod == 4) {
			if($fp = @fopen($filename, 'rb')) {
				if(function_exists('fpassthru') && ($readmod == 3 || $readmod == 4)) {
					@fpassthru($fp);
				} else {
					echo @fread($fp, filesize($filename));
				}
			}
			@fclose($fp);
		} else {
			@readfile($filename);
		}
		@flush(); @ob_flush();
	}

	private static function _getRemoteFile($file) {
		global $_G;

		@set_time_limit(0);
		if(!@readfile($_G['setting']['ftp']['attachurl'] . 'forum/' . $file)) {
			$ftp = ftpcmd('object');
			$tmpfile = @tempnam($_G['setting']['attachdir'], '');
			if($ftp->ftp_get($tmpfile, 'forum/'.$file, FTP_BINARY)) {
				@readfile($tmpfile);
				@unlink($tmpfile);
			} else {
				@unlink($tmpfile);
				return FALSE;
			}
		}

		return TRUE;
	}

	private static function _checkXSendFile($file) {
		$filename = self::_getFullPath($file);
		$xsendfile = getglobal('config/download/xsendfile');
		if(!empty($xsendfile)) {
			$type = intval($xsendfile['type']);
			$cmd = '';
			switch ($type) {
				case 1:
					$cmd = 'X-Accel-Redirect';
					$url = $xsendfile['dir'] . $file;
					break;
				case 2:
					$cmd = $_SERVER['SERVER_SOFTWARE'] <'lighttpd/1.5' ? 'X-LIGHTTPD-send-file' : 'X-Sendfile';
					$url = $filename;
					break;
				case 3:
					$cmd = 'X-Sendfile';
					$url = $filename;
					break;
			}
			if($cmd) {
				dheader("$cmd: $url");
				exit();
			}
		}
	}
}