/** * 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]); }
/** * 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; }