<?php


/**
 * 添付ファイルを管理するクラス。
 * 
 * Pageごとにシングルトンのようにふるまう。
 */
class Attach
{
	protected $wikiid;
	protected $pagename;
	
	
	/**
	 * インスタンスを取得する。
	 */
	static function getinstance($pagename, $id = WIKIID)
	{
		return new Attach($pagename, $id);
	}
	
	
	/**
	 * コンストラクタ。
	 */
	protected function __construct($pagename, $id)
	{
		$this->wikiid = $id;
		$this->pagename = $pagename;
	}
	
	
	/**
	 * ページに添付されているファイルを列挙する。
	 * 
	 * @return	array(string)	ファイル名の配列。
	 */
	function getlist()
	{
		$db = DataBase::getinstance($this->wikiid);
		
		$pagename = $db->escape($this->pagename);
		$query  = "SELECT filename FROM attach WHERE pagename = '$pagename'";
		$query .= " ORDER BY filename ASC";
		$result = $db->query($query);
		$ret = array();
		while($row = $db->fetch($result)){
			$ret[] = $row['filename'];
		}
		return $ret;
	}
	
	
	/**
	 * ファイル名を変更する。
	 * 
	 * @param	string	$old	元のファイル名
	 * @param	string	$new	新しいファイル名
	 * @return	bool	変更が成功すればtrue、失敗すればfalse。
	 */
	function rename($old, $new)
	{
		$db = DataBase::getinstance($this->wikiid);
		
		$pagename = $db->escape($this->pagename);
		$_old = $db->escape($old);
		$_new = $db->escape($new);
		$query  = "UPDATE OR IGNORE attach SET filename = '$_new'";
		$query .= " WHERE (pagename = '$pagename' AND filename = '$_old')";
		$db->query($query);
		if($db->changes() != 0){
			$this->mail("ファイル {$old} が {$new} にリネームされました。");
			return true;
		}
		else{
			return false;
		}
	}
	
	
	/**
	 * ファイルが存在するかどうかを確認する。
	 * 
	 * @param	string	$filename
	 * @return	bool
	 */
	function isexist($filename)
	{
		$db = DataBase::getinstance($this->wikiid);
		
		$_pagename = $db->escape($this->pagename);
		$_filename = $db->escape($filename);
		$query  = "SELECT filename FROM attach";
		$query .= " WHERE (pagename = '$_pagename' AND filename = '$_filename')";
		return (bool)$db->fetch($db->query($query));
	}
	
	
	/**
	 * ファイルを別ページに移動させる。
	 * 
	 * @param	string	$newname
	 * @return	bool	移動先ページにファイルが存在するときはfalse
	 */
	function move($newname)
	{
		$db = DataBase::getinstance($this->wikiid);
		$db->begin();
		
		$_from = $db->escape($this->pagename);
		$_to = $db->escape($newname);
		$query = "SELECT count(*) FROM attach WHERE pagename = '$_to'";
		if($db->fetch($db->query($query)) == 0){
			$db->commit();
			return false;
		}
		
		$query  = "UPDATE attach SET pagename = '$_to'";
		$query .= " WHERE pagename = '$_from'";
		$db->fetch($db->query($query));
		$db->commit();
		return true;
	}
	
	
	protected function mail($mes)
	{
		$subject = '[KinoWiki-' . $this->wikiid . '] ' . $this->pagename;
		$text[] = $mes;
		$text[] = '';
		$text[] = 'WikiID: ' . WIKIID;
		$text[] = date('Y-m-d H:i:s', TIME);
		$text[] = 'REMOTE_HOST: ' . gethostbyaddr($_SERVER['REMOTE_ADDR']);
		$text[] = 'REMOTE_ADDR: ' . $_SERVER['REMOTE_ADDR'];
		sendmail($subject, join("\n", $text));
	}
}



/**
 * 添付ファイルを表すクラス。
 * 
 * WikiIDごとにシングルトン。
 * ファイルごとにシングルトンのようにふるまう。
 */
class AttachedFile
{
	protected $filename;
	protected $pagename;
	protected $wikiid;
	
	
	function getfilename(){ return $this->filename; }
	function getpagename(){ return $this->pagename; }
	
	
	/**
	 * インスタンスを取得する。Pageごとにシングルトン。
	 */
	static function getinstance($filename, $pagename, $id = WIKIID)
	{
		return new AttachedFile($filename, $pagename, $id);
	}
	
	
	/**
	 * コンストラクタ。
	 */
	protected function __construct($filename, $pagename, $id)
	{
		$this->filename = $filename;
		$this->pagename = $pagename;
		$this->wikiid = $id;
	}
	
	
	/**
	 * ファイルを保存する。
	 * 
	 * @param	const string	&$bin	ファイルの内容。
	 * @return	bool	成功すればtrue、すでにファイルがあればfalse。
	 */
	function set(&$bin)
	{
		$db = DataBase::getinstance($this->wikiid);
		
		$filename = $db->escape($this->filename);
		$pagename = $db->escape($this->pagename);
		$data = $db->escape($bin);
		$size = strlen($bin);
		$query  = "INSERT OR IGNORE INTO attach";
		$query .= " (pagename, filename, binary, size, timestamp, count)";
		$query .= " VALUES('$pagename', '$filename', '$data', $size, " . TIME . ", 0)";
		$db->query($query);
		if($db->changes() != 0){
			$this->mail("ファイル {$this->filename} が添付されました。");
			return true;
		}
		else{
			return false;
		}
	}
	
	
	/**
	 * ファイルを削除する。
	 */
	function delete()
	{
		$db = DataBase::getinstance($this->wikiid);
		
		$filename = $db->escape($this->filename);
		$pagename = $db->escape($this->pagename);
		
		$query  = "DELETE FROM attach";
		$query .= " WHERE (pagename = '$pagename' AND filename = '$filename')";
		$db->query($query);
		$this->mail("ファイル {$this->filename} が削除されました。");
	}
	
	
	/**
	 * ファイル内容を取得する。
	 * 
	 * @param	bool	$count	取得時にカウンタを回すときはtrue
	 * @return	string	ファイルがないときはnull。
	 */
	function getdata($count = false)
	{
		$db = DataBase::getinstance($this->wikiid);
		$db->begin();
		
		$filename = $db->escape($this->filename);
		$pagename = $db->escape($this->pagename);
		
		$query  = "SELECT binary FROM attach";
		$query .= " WHERE (pagename = '$pagename' AND filename = '$filename')";
		$row = $db->fetch($db->query($query));
		if($count){
			$query  = "UPDATE attach SET count = count + 1";
			$query .= " WHERE (pagename = '$pagename' AND filename = '$filename')";
			$db->query($query);
		}
		$db->commit();
		return $row != false ? $row['binary'] : null;
	}
	
	
	/**
	 * ファイルサイズを取得する。
	 */
	function getsize()
	{
		$ret = $this->getcol('size');
		return $ret !== false ? $ret : 0;
	}
	
	
	/**
	 * タイムスタンプを取得する。
	 */
	function gettimestamp()
	{
		$ret = $this->getcol('timestamp');
		return $ret !== false ? $ret : null;
	}
	
	
	/**
	 * ダウンロード数を取得する。
	 */
	function getcount()
	{
		$ret = $this->getcol('count');
		return $ret !== false ? $ret : 0;
	}
	
	
	protected function getcol($col)
	{
		$db = DataBase::getinstance($this->wikiid);
		
		$filename = $db->escape($this->filename);
		$pagename = $db->escape($this->pagename);
		
		$query  = "SELECT $col FROM attach";
		$query .= " WHERE (pagename = '$pagename' AND filename = '$filename')";
		$row = $db->fetch($db->query($query));
		return $row != false ? $row[$col] : false;
	}
	
	
	protected function mail($mes)
	{
		$subject = '[KinoWiki-' . $this->wikiid . '] ' . $this->pagename;
		$text[] = $mes;
		sendmail($subject, join("\n", $text));
	}
}


?>