<?php


if(!defined('APP_INCLUDE')){ die('invalid inclusion'); }
 
include_once "upload_dir.php";

class FTP_log extends UploadDir {	
	var $FTP_connection;
	var $Local_pathname;
	var $RemotePathname;
	var $FTP_files_accept;
	var $FTP_files_deny;
	var $Seektime;
	var $username;
	var $password;
	var $servername;
	var $current_file_size;
	var $mode;
	var $port;

	/* function FTP_log($servername, $username, $password, $pathname)
	 * $servername is used to identify the target machiene.
	 * $username is used to identify the user on the target machine.
	 * $password is used to verify the user on targeted machine.
	 * $pathname is used to use the specified path on target machine.
	 * 
	 * $pathname is split into an array.
	 * 
	 * $mode is used to set the connection mode to: 0 = Active or 1 = Passive (default set to Active)
	 * $port is used to use a specified port on target machine (default set to 21)
	 */
	function FTP_log($servername, $username, $password, $Remote_pathname, $files_accept, $files_deny, $local_pathname, $seektime, $port = 21, $mode = 0){
		
		$this->Seektime = $seektime;
		$this->Local_pathname = $local_pathname;
		$this->FTP_files_accept = $files_accept;
		$this->FTP_files_deny = $files_deny;
		$this->RemotePathname = $Remote_pathname;
		$this->username = $username;
		$this->password = $password;
		$this->servername = $servername;
		$this->mode = $mode;
		$this->port = $port;
		
		$this->FTP_connect();
		
        if (!empty($files_accept)) {
		    if($files_accept[0] != "("){
			    $this->FTP_files_accept = "[".$files_accept."]";
		    }
        }
        if (!empty($files_deny)) { 
		    if($files_deny[0] != "("){
			    $this->FTP_files_deny = "[".$files_deny."]";
		    }
        }

		
	}
    /**
    * @desc This is called first if the user wants to download
    */
	function Files_Download($path = "", $subdir= "") {
		global $import;
		
		if($path == ""){
			$path = $this->RemotePathname;
		} else {			
			$subdir = $subdir.$this->GetFilename($path)."/";
		}
		if($this->Local_pathname[(strlen($this->Local_pathname)-1)] != "/"){
			$this->Local_pathname .= "/";
		}
		if (substr($path,-1)!="/") {
			$path .="/";
		}
		if(!is_dir($this->Local_pathname.$subdir)){
				mkdir($this->Local_pathname.$subdir);
		}
		
		$s = time();
		
		# returns a ls -lha files array list.


		$files_data = $this->GetFileList($path);	
		
		# decode a ls -lha files array list. and only return a array with files.
		$files = $this->DecodeFilesData($files_data);
		
		# filter the files array list. and only return a array with files which are possible log files.
		$filelist = $this->FilterFileList($files);		
		if(!is_array($filelist)){ $filelist = []; }
		
		foreach($filelist as $key => $filepath){

			$import->StopOrContinue();

			if ($filepath== '..' || $filepath == '.' || $filepath == "{$this->RemotePathname}." || $filepath == "{$this->RemotePathname}..") {
				continue;
			}

			$filename = $this->GetFilename($filepath);

			if($this->full_file_data_list[$filename]['isDir'] == 1){
				$this->Files_Download($filepath,$subdir);
				continue;
			}

			if($this->ShouldDownload($filepath,$subdir)){
				$this->DownloadFile($filepath,$subdir);
			}else{
				//echo "Skip file:$filepath\n";
				continue;
			}
		}
	}
	function FTP_connect(){
		if(!$this->FTP_connection = @ftp_connect($this->servername, $this->port, 90)){
			//die("The specified remote FTP host doesn't exist.");
			echo '{ "Status" : "Warning", "Message" : "The specified remote FTP host doesn\'t exist."}';
			exit();
		}
		if(!@ftp_login($this->FTP_connection, $this->username, $this->password)){
			//die("The username or password is incorrect.");
			echo '{ "Status" : "Warning", "Message" : "The username or password is incorrect."}';
			exit();
		}

		$this->systype =  ftp_systype($this->FTP_connection);

		if($this->mode === 1){
			ftp_pasv($this->FTP_connection,TRUE);
		}
	}
	
	
	/* function DecodeFilesData($list)
	 * $list The list that needs to be filtered 
	 * 
	 * This function is called to filter out the list which is neded an not neded.
	 * returns a array with files.
	 * */
	function DecodeFilesData($list){
		 if ($list==false) {
            return false;    
        }		
		$mons = array(1 => "Jan", 2 => "Feb", 3 => "Mar", 4 => "Apr", 5 => "May", 6 => "Jun", 7 => "Jul", 8 => "Aug", 9 => "Sep", 10 => "Oct", 11 => "Nov", 12 => "Dec");

		$files = [];

		foreach ($list as $current) {
	    	switch ($this->systype) {
	        	case "Windows_NT":
		        	ereg("([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)",$current,$data);
			        if (is_array($data)) {
			        	if ($data[3]<70) { $data[3]+=2000; } else { $data[3]+=1900; } // 4digit year fix
			            
			        	$file = $data[8];
						$this->full_file_data_list[$file]['bytes'] = $data[7];			
						$this->full_file_data_list[$file]['date'] = ($data[1]." ".$data[2]." ".$data[3]);
						$this->full_file_data_list[$file]['timestamp'] = strtotime($data[1]."/".$data[2]."/".$data[3]." ".$data[4].":".$data[5].$data[6]);
						

						if($data[7]=="<DIR>"){
							$this->full_file_data_list[$file]['isDir'] = 1;
						} else {
							$this->full_file_data_list[$file]['isDir'] = 0;
						}
						
			            $files[] = $file;
			            
			        }
	         		break;

	         	//case "UNIX":
	         	default:
					$data = preg_split('/\s+/', $current);
					
					# $data[4] = Bytes
					# $data[5] = Month
					# $data[6] = Day
					# $data[7] = Time / Year
					# $data[8] = file
					
					$file = $data[8];
					$this->full_file_data_list[$file]['bytes'] = $data[4];			
					$this->full_file_data_list[$file]['date'] = ($data[5]." ".$data[6]." ".$data[7]);	
					$this->full_file_data_list[$file]['timestamp'] = strtotime($data[5]." ".$data[6]." ".$data[7]);
					if (strpos($data[7], ":")!==false) {
						$h = explode(":",$data[7]);
						$t = mktime($h[0],$h[1],0, array_search($data[5],$mons),$data[6], date("Y"));
						# there is only a time, no year, so we have to check if this file belongs to this year or the previous year
						//if (strtotime($data[5]." ".$data[6]." ".$data[7]) > time()) {						
						if ($t > (time()+86400)) {
							# this is in the future, that can't be right, so add the previous year
							$year = date("Y")-1;
							//$this->full_file_data_list[$file]['timestamp'] = strtotime($data[5]." ".$data[6]." ".$data[7]. " $year");
							$this->full_file_data_list[$file]['timestamp'] = mktime($h[0],$h[1],0, array_search($data[5],$mons),$data[6], $year);
						}
					}
					if(substr($data[0],0,1) == "d"){
						$this->full_file_data_list[$file]['isDir'] = 1;
					} else {
						$this->full_file_data_list[$file]['isDir'] = 0;
					}	
					
					
					$files[] = $file;
					
	         		break;
	    	}
	   	}
		return $files;
	}
	
	/* function FilterFileList($list)
	 * $list The list that needs to be filtered 

	 * 
	 * This function is called to filter out the list which is neded an not neded.
	 * 
	 * */
	function FilterFileList($list){
        if ($list==false) {
            return false;    
        }
		
		# first make sure remote pathname has a trailing slash
		if (substr($this->RemotePathname, -1)!=="/") {
			$this->RemotePathname = $this->RemotePathname."/";
		}
		
		foreach($list as $key => $file) {
			$list[$key] = str_replace($this->RemotePathname, "", $file);
		}
		
        if (!empty($this->FTP_files_accept)) {
            $list = preg_grep($this->FTP_files_accept, $list);
        }
		
        if (!empty($this->FTP_files_deny)) {
		    $list = preg_grep($this->FTP_files_deny, $list, PREG_GREP_INVERT);
        }
		
		foreach($list as $key => $file) {
			$list[$key] = $this->RemotePathname.$file;
		}
		
		return $list;
	}
	/* function GetFileList()
	 * 
	 * this function gets a list of availible files and directory's on the remote machine.
	 * */	
	function GetFileList($remotePath){
		//echoConsoleSafe("ftp_rawlist({$this->FTP_connection},{$remotePath})".date("H:i:s",time()),true);
		$list = ftp_rawlist($this->FTP_connection,$remotePath);
		//dump($list);
		//exit();
		return $list;
	}
	/* function ChangeRemotepath($remotePath)
	 * $remotePath The path directory to change to.
	 * 
	 * This function changes the remote path on the target machine.
	 */
	function ChangeRemotepath($remotePath){
		return @ftp_chdir($this->FTP_connection, $remotePath);
	}
	/* function IsDirectory($directory)
	 * $directory The directory to check
	 * 
	 * This function checks if the thing is a directory
	 */
	function IsDirectory($directory){
		if($this->ChangeRemotepath($directory)){
			$this->ChangeRemotepath("..");			
			return true;
		}
		return false;
	}
	
	/* function ShouldDownload($filename)
	 * $filename the file that needs checking in order to be downloaded.
	 * 
	 * this function checks if a file should be downloaded.
	 * */
	function ShouldDownload($filepath,$subdir=""){
	
		$filename=$this->GetFilename($filepath);
		if($this->full_file_data_list[$filename]["bytes"] == @filesize($this->Local_pathname.$subdir.$filename)){
			//echoWarning("skip because we have the file: $filename<br>");
			return false;
		}		
		if(($this->Seektime - $this->full_file_data_list[$filename]["timestamp"]) > 86400){
			// echo("skip because seektime: $filename<br>".$this->Seektime."-". $this->full_file_data_list[$filename]["timestamp"]."\n");
			// echo(date("Y-m-d H;i;s",$this->Seektime)."\n");
			//echo(date("Y-m-d H;i;s",$this->full_file_data_list[$filename]["timestamp"])."\n");
			return false;
		}
		
		return true;	
	}
	
	/* function DownloadFile($filename)
	 * $filename The file that will be downloaded.
	 * 
	 * This function does the actual downloading of the file.
	 * */
	function DownloadFile($filepath,$subdir){
		$filename=$this->GetFilename($filepath);		
		$resumepos = $this->GetResumePos($filename,$subdir);
		$destination = $this->Local_pathname.$subdir.$filename;
		
        $source = $filepath;
		$this->current_file_size = ftp_size($this->FTP_connection, $source);
		echoConsoleSafe("PHP using ".(memory_get_usage()/1024/1024)." mb", true);
		echoConsoleSafe('Downloading '.$source.'  ('.$this->PrettySize($this->current_file_size).')... <br>', true);

		lgflush();
		ftp_get($this->FTP_connection, $destination, $source, FTP_BINARY, $resumepos);
	}

	/* function GetResumePos($filename)
	 * $filename The file from which to get the resume position.
	 * 
	 * This function gets the resume postition for the named file.
	 * */
	function GetResumePos($filename, $subdir){
		if(!file_exists($this->Local_pathname.$subdir.$filename)){
			return 0;
		}
		if($this->IsSameFile($filename, $subdir)){
			return @filesize($this->Local_pathname.$subdir.$filename);
		}
		return 0;
	}
	/* function IsSameFile($filename)
	 * $filename The file to be checked.
	 * 
	 * This function checks if the remote file is the same as the local file.
	 */
	function IsSameFile($filename, $subdir){
		$this->DownloadPart($filename,$subdir);
		$file_pointer = fopen($this->Local_pathname.$subdir.$filename, 'r');
		$file_pointer_temp = fopen($this->Local_pathname.$subdir.$filename.".temp", 'r');
		$MD5_file = md5(fgets($file_pointer));
		$MD5_file_temp = md5(fgets($file_pointer_temp));
		fclose($file_pointer_temp);
        fclose($file_pointer);
		
        unlink($this->Local_pathname.$subdir.$filename.".temp");
		
		if($MD5_file == $MD5_file_temp){
			return true;
		}
		return false;
	}
	/* function DownloadPart($filename)
	 * $filename The file that needs to be downlaoded for a little part.
	 * 
	 * This function checks if the actual remote and local file are still the same.
	 */
	function DownloadPart($filename,$subdir){
		ftp_set_option($this->FTP_connection, FTP_TIMEOUT_SEC, 1);
		$fp = fopen($this->Local_pathname.$subdir.$filename.".temp",'w');
		
		# Passive mode already set after connection
		//ftp_pasv($this->FTP_connection,TRUE);
        $remote_data = ftp_nb_fget($this->FTP_connection, $fp, $this->RemotePathname.$subdir.$filename, FTP_BINARY, 0);
        //$remote_data = ftp_nb_get($this->FTP_connection, $this->Local_pathname.$subdir.$filename.".temp", $this->RemotePathname.$subdir.$filename, FTP_BINARY, 0);
		while($remote_data == FTP_MOREDATA){
			if(filesize($this->Local_pathname.$subdir.$filename.".temp") >= 1024){	
				break;
			}
			$remote_data = ftp_nb_continue($this->FTP_connection);
		}
        ftp_close($this->FTP_connection);
        fclose($fp);
        $this->FTP_connect();
		return;
	}
	/* function PathSeparator($filename)
	 * $filename The path and file that needs to be separated.
	 * 
	 * This function separates the pathh from the file and returns it.
	 */
	function GetFilename($filename){
		$filename = pathinfo($filename);
		$filename = $filename['basename'];
		return $filename;
	}
    
    /**                                 
    * @desc This function takes the byte size and returns a string that is human readable 
    */
    function PrettySize($bytes) {
        if ($bytes > (1024*1024*1024)) {
            # we're gonna report gigabytes
            $size = number_format(($bytes/(1024*1024*1024)),2) . " GB";
        } else if ($bytes > (1024*1024)) {
            $size = number_format(($bytes/(1024*1024)),2) . " MB";
        } else if ($bytes > 1024) {
            $size = number_format(($bytes/1024),2) . " KB";
        } else {
            $size = $bytes . " Bytes";
        }
        return $size;   
    }
}
?>