Esempio n. 1
0
	/**
	 * Get an associative array of all metadata associated to the requested file.
	 *
	 * @param string $file
	 *
	 * @return array
	 * @throws \Exception
	 */
	public function getMetas($file){
		$allkeys = ['filename', 'hash', 'modified', 'size'];

		if($this->_contents === null){

			$this->_contents = [];

			$remotefile = $this->_dir . '.ftpmetas';
			$f = md5($remotefile);

			$this->_local = Factory::File('tmp/remotefile-cache/' . $f);

			if(
				(!$this->_local->exists()) ||
				($this->_local->exists() && $this->_local->getMTime() + 1800 < DateTime::NowGMT())
			){
				// Only try to open the remote file if it exists.
				if(ftp_size($this->_ftp->getConn(), $remotefile) != -1){
					// The file doesn't exist OR the file does but it hasn't been modified in the past 30 minutes.
					$this->_local->putContents('');
					ftp_get($this->_ftp->getConn(), $this->_local->getFilename(), $remotefile, FTP_BINARY);
				}
			}


			if(!$this->_local->exists()){
				// The remote file doesn't exist, so nothing was downloaded.
				// Just return a blank array.
				return array_merge($allkeys, ['filename' => $file]);
			}

			// Read this CSV file into the contents array.
			$fh = fopen($this->_local->getFilename(), 'r');
			if(!$fh){
				throw new \Exception('Unable to open ' . $this->_local->getFilename() . ' for reading.');
			}
			$line    = 0;
			$map     = [];
			$headers = [];
			do{
				$data = fgetcsv($fh, 2048);

				// Meh.  Could do this inside a standard while statement, but same diff.
				if($data === null) break;
				if($data === false) break;

				$line++;
				if($line == 1){
					// This is the header.
					$map = $data;
					foreach($data as $k => $v){
						$headers[$v] = $k;
					}

					foreach($allkeys as $key){
						if(!isset($headers[$key])){
							$map[] = $key;
							$headers[$key] = -1;
						}
					}
				}
				else{
					$assoc = [];
					foreach($map as $k => $v){
						$assoc[$v] = isset($data[$k]) ? $data[$k] : '';
					}
					if(!isset($assoc['filename'])){
						// Invalid CSV input.
						fclose($fh);
						return array_merge($allkeys, ['filename' => $file]);
					}

					$this->_contents[ $assoc['filename'] ] = $assoc;
				}
			}
			while(true);
		}

		return isset($this->_contents[$file]) ? $this->_contents[$file] : array_merge($allkeys, ['filename' => $file]);
	}
Esempio n. 2
0
	/**
	 * Get the temporary local version of the file.
	 * This is useful for doing operations such as hash and identicalto.
	 *
	 * @return FileLocal
	 */
	protected function _getTmpLocal() {
		if ($this->_tmplocal === null) {
			$f = md5($this->getFilename());

			// Gotta love obviously-named flags.
			$needtodownload = true;

			$this->_tmplocal = Filestore\Factory::File('tmp/remotefile-cache/' . $f);

			// File exists already!  Check and see if it needs to be redownloaded.
			if ($this->cacheable && $this->_tmplocal->exists()) {
				// Lookup this file in the system cache.
				$systemcachedata = Cache::Get('remotefile-cache-header-' . $f);
				if ($systemcachedata && isset($systemcachedata['headers'])) {
					// I can only look them up if the cache is available.

					// First check will be the expires header.
					if(isset($systemcachedata['headers']['Expires']) && strtotime($systemcachedata['headers']['Expires']) > time()){
						$needtodownload = false;
						// And set the headers!
						// This is required
						$this->_headers = $systemcachedata['headers'];
						$this->_response = $systemcachedata['response'];
					}
					// Next, try ETag.
					elseif ($this->_getHeader('ETag') && isset($systemcachedata['headers']['ETag'])) {
						$needtodownload = ($this->_getHeader('ETag') != $systemcachedata['headers']['ETag']);
					}
					// No?  How 'bout 
					elseif ($this->_getHeader('Last-Modified') && isset($systemcachedata['headers']['Last-Modified'])) {
						$needtodownload = ($this->_getHeader('Last-Modified') != $systemcachedata['headers']['Last-Modified']);
					}
					// Still no?  The default is to download it anyway.
				}
			}

			if ($needtodownload || !$this->cacheable) {
				// Make sure that the headers are updated, this is a requirement to use the 302 tag.
				$this->_getHeaders();
				if(($this->_response == '302' || $this->_response == '301') && $this->_redirectFile !== null){
					$this->_tmplocal = $this->_redirectFile->_getTmpLocal();
				}
				else{
					// BTW, use cURL.
					$curl = curl_init();
					curl_setopt_array(
						$curl, array(
							CURLOPT_HEADER         => false,
							CURLOPT_NOBODY         => false,
							CURLOPT_RETURNTRANSFER => true,
							CURLOPT_URL            => $this->getURL(),
							CURLOPT_HTTPHEADER     => \Core::GetStandardHTTPHeaders(true),
						)
					);

					$result = curl_exec($curl);
					if($result === false){
						switch(curl_errno($curl)){
							case CURLE_COULDNT_CONNECT:
							case CURLE_COULDNT_RESOLVE_HOST:
							case CURLE_COULDNT_RESOLVE_PROXY:
								$this->_response = 404;
								return $this->_tmplocal;
								break;
							default:
								$this->_response = 500;
								return $this->_tmplocal;
								break;
						}
					}

					curl_close($curl);

					// Copy the data down to the local file.
					$this->_tmplocal->putContents($result);
				}

				// And remember this header data for nexttime.
				Cache::Set(
					'remotefile-cache-header-' . $f,
					[
						'headers'  => $this->_getHeaders(),
						'response' => $this->_response,
					]
				);
			}
		}

		return $this->_tmplocal;
	}