<?php
class Fetch {
	static function ftp($url, $file = NULL) {
		$url = parse_url($url);
		if(!isset($url['scheme']) || $url['scheme'] != 'ftp') {
			throw new Exception('Only FTP URLs are supported');
		}
		if(!isset($url['host'])) {
			throw new Exception('Hostname not present in the URL');
		}
		if(!isset($url['path'])) {
			throw new Exception('Path component not present in the URL');
		}
		if(!isset($url['port'])) {
			$url['port'] = 21;
		}
		if(!isset($url['user'])) {
			$url['user'] = 'anonymous';
		}
		if(!isset($url['pass'])) {
			$url['pass'] = 'anonymous@mpk.jacekk.net';
		}
		if($file === NULL) {
			$file = basename($url['path']);
		}
		
		$localTime = -1;
		$localSize = -1;
		if(is_file($file)) {
			$localTime = filemtime($file);
			$localSize = filesize($file);
		}
		
		$ftp = FtpConnection::create($url['host'], $url['port'], $url['user'], $url['pass']);
		$remoteSize = $ftp->size($url['path']);
		$remoteTime = $ftp->mdtm($url['path']);
		
		$updated = FALSE;
		
		if($localTime >= $remoteTime && $localSize == $remoteSize) {
			return FALSE;
		}
		
		if(file_exists($file.'.tmp')) {
			unlink($file.'.tmp');
		}
		$ftp->get($file.'.tmp', $url['path'], FTP_BINARY);
		touch($file.'.tmp', $remoteTime);
		if(!rename($file.'.tmp', $file)) {
			throw new Exception('Temporary file rename failed');
		}
		
		return TRUE;
	}
	
	static function parse_http_headers($headers) {
		$hasHeader = FALSE;
		foreach($headers as $header) {
			if(substr($header, 0, 5) === 'HTTP/') {
				$code = substr($header, 9, 3);
				if($code === '304') {
					return NULL;
				} elseif(substr($code, 0, 1) == '2') {
					$hasHeader = TRUE;
				}
			} elseif($hasHeader && strtolower(substr($header, 0, 15)) === 'last-modified: ') {
				return strptime(substr($header, 15), 'D, d M Y H:i:s T');
			}
		}
		return FALSE;
	}
	
	static function generic($url, $file = NULL) {
		if($file === NULL) {
			$file = basename($url['url']);
		}
		
		$context = [];
		if(is_file($file)) {
			$file_date = filemtime($file);
			$context['http'] = [
				'header' => [
					'If-Modified-Since: '.gmdate('D, d M Y H:i:s T', $file_date),
				],
			];
		}
		
		$data = file_get_contents($url, FALSE, stream_context_create($context));
		$remoteTime = FALSE;
		if(isset($http_response_header) && is_array($http_response_header)) {
			$remoteTime = self::parse_http_headers($http_response_header);
			if($remoteTime === NULL) {
				return FALSE;
			}
		}
		
		if($data === FALSE) {
			throw new Exception('URL fetch failed');
		}
		if(file_put_contents($file.'.tmp', $data) === FALSE) {
			throw new Exception('Temporary file creation failed');
		}
		if($remoteTime !== FALSE) {
			touch($file.'.tmp', $remoteTime);
		}
		if(!rename($file.'.tmp', $file)) {
			throw new Exception('Temporary file rename failed');
		}
		
		return TRUE;
	}
	
	static function auto($url, $file = NULL) {
		if($file === NULL) {
			$file = basename($url['url']);
		}
		if(substr($url, 0, 4) == 'ftp:') {
			return self::ftp($url, $file);
		}
		return self::generic($url, $file);
	}
}