connection = @ssh2_connect($host, $port); if (! $this->connection){ throw new Exception("Could not connect to $host on port $port."); } } /** * @param string $username * @param string $password * * @return bool * @throws Exception */ public function login($username, $password) { if (! @ssh2_auth_password($this->connection, $username, $password)){ throw new Exception( 'Could not authenticate with username '.$username . (empty($password)?' and no password': ' and password ***.') ); } $this->sftp = @ssh2_sftp($this->connection); if (! $this->sftp){ throw new Exception("Could not initialize SFTP subsystem."); } return true; } /** * @param string $local_file * @param string $remote_file * * @return bool * @throws Exception */ public function uploadFile($local_file, $remote_file) { $sftp = $this->sftp; $stream = @fopen('ssh2.sftp://'.(int)$sftp.$remote_file, 'w'); if (! $stream){ throw new Exception("Could not open file: $remote_file"); } $data_to_send = @file_get_contents($local_file); if ($data_to_send === false){ throw new Exception("Could not open local file: $local_file."); } if (@fwrite($stream, $data_to_send) === false){ throw new Exception("Could not send data from file: $local_file."); } @fclose($stream); return true; } /** * @param string $remote_file * * @return array * @throws Exception */ public function scanFilesystem($remote_file) { $sftp = $this->sftp; $dir = 'ssh2.sftp://'.(int)$sftp.$remote_file; $tempArray = array(); $handle = @opendir($dir); if(empty($handle)) { throw new Exception("Could not read dir: $remote_file."); } if(!empty($handle)){ // List all the files while (false !== ($file = readdir($handle))) { if(substr("$file", 0, 1) !== '.'){ if(is_dir($file)){ // $tempArray[$file] = $this->scanFilesystem("$dir/$file"); }else{ $tempArray[] = $file; } } } closedir($handle); } return $tempArray; } /** * @param string $remote_file * @param string $local_file * * @return bool * @throws Exception */ public function receiveFile($remote_file, $local_file) { $sftp = $this->sftp; $stream = @fopen('ssh2.sftp://'.(int)$sftp.$remote_file, 'r'); if (! $stream){ throw new Exception("Could not open file: $remote_file"); } $contents = ''; $size = filesize('ssh2.sftp://'.(int)$sftp.$remote_file); if($size <= 0 || $size > 8192) { $size = 8192; } while(($content = fread($stream, $size)) !== false) { $contents .= $content; if($content ==='') { break; } } file_put_contents ($local_file, $contents); @fclose($stream); return true; } /** * @param $remote_file * * @return bool * @throws Exception */ public function deleteFile($remote_file){ $sftp = $this->sftp; if(!@unlink('ssh2.sftp://'.(int)$sftp.$remote_file)) { throw new Exception("Could not delete file: $remote_file"); } return true; } } /** * sofortimport for 'payone' * import from .csv file at specified location * * Class payone */ class payone { const COL_DIVIDER = ";"; const DEFAULT_N_DAYS = 5; const DEFAULT_FILE = '/tmp/default-payone.csv'; /** @var Application $app */ private $app; private $requiredHeaders = ['payment', 'currency', 'timestamp', 'txid']; private $optionalHeaders = ['reference', 'clearingtype', 'clearingsubtype', 'userid']; /** * the file handle * * @var resource */ private $handle = null; /** * just as fallback, if all fails * on delete, the file handle should * be closed */ public function __destruct() { $this->closeFile(); } protected function FTPisDir(&$conn_id, $dir ) { $akt = ftp_pwd( $conn_id ); if ( @ftp_chdir( $conn_id, $dir ) ) { @ftp_chdir( $conn_id, $akt ); return true; } return false; } /** * @param string $file * @param bool $ssl * @param string $url * @param int $port * @param string $username * @param string $pw * @param string $subdir * * @return bool */ protected function FTPDeleteFile($file, $ssl, $url, $port, $username, $pw, $subdir = '') { $aktfolder = ''; if(empty($port)) { $port = 21; } if($ssl) { $conn_id = ftp_ssl_connect($url, $port); } else{ $conn_id = ftp_connect($url, $port); } if(!$conn_id) { $this->fehler[] = 'FTP-Verbindung fehlgeschlagen zu '.$url.':'.$port; return false; } $login_result = ftp_login($conn_id, $username, $pw); if($login_result) { if(!empty($subdir) && $subdir !== '/' && $subdir !== '.') { $aktfolder = @ftp_pwd($conn_id); if(!@ftp_chdir($conn_id, $subdir)) { ftp_close($conn_id); $this->fehler[] = $subdir.' auf FTP-Server nicht gefunden'; return false; } } if (ftp_delete($conn_id, $file)) { if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && !empty($aktfolder)) { @ftp_chdir($conn_id, $aktfolder); } ftp_close($conn_id); return true; } } else { $this->fehler[] = 'FTP-Login fehlgeschlagen zu '.$url.':'.$port.' mit User '.$username; } ftp_close($conn_id); return false; } /** * @param bool $ssl * @param string $url * @param string $port * @param string $username * @param string $pw * @param string $subdir * @param string $prefix * * @return array|bool */ protected function FTPGetFileList($ssl, $url, $port, $username, $pw, $subdir = '', $prefix = '') { if(empty($port)) { $port = 21; } $port = (int)$port; $aktfolder = ''; if($ssl) { $conn_id = ftp_ssl_connect($url, $port); } else{ $conn_id = ftp_connect($url, $port); } if(!$conn_id) { $this->fehler[] = 'Verbindung fehlgeschlagen zu '.$url .':'. $port; return false; } $login_result = ftp_login($conn_id, $username, $pw); if($login_result) { ftp_pasv($conn_id, true); if(!empty($subdir) && $subdir !== '/' && $subdir !== '.') { $aktfolder = ftp_pwd($conn_id); if(!@ftp_chdir($conn_id, $subdir)) { $this->fehler[] = $subdir.' nicht gefunden'; ftp_close($conn_id); return false; } } $Liste = ftp_nlist($conn_id, "-dF "."."); if(empty($Liste) || count($Liste)<= 1) { $Liste = ftp_nlist($conn_id, "."); } if($Liste !== false) { if(!empty($Liste)) { foreach($Liste as $k => $v) { if(strpos($v,'./') === 0) { $v = substr($v, 2); $Liste[$k] = $v; } if($v === '' || $v === '.' || $v === '..') { unset($Liste[$k]); continue; } if($prefix != '') { if(stripos($v, $prefix) !== 0) { unset($Liste[$k]); continue; } if(substr($v, -1) === '/' || (strpos($v,'.') === false && $this->FTPisDir($conn_id, $v))) { unset($Liste[$k]); continue; } } if(substr($v,-1) === '/' && $this->FTPisDir($conn_id, $v)) { unset($Liste[$k]); continue; } } } if(!empty($subdir) && $subdir !== '/' && $subdir !== '.') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); return $Liste; } $this->fehler[] = "Fehler beim Lesen von $url $subdir"; } else{ $this->fehler[] = 'FTP Login fehlgeschlagen fehlgeschlagen'; ftp_close($conn_id); return false; } ftp_close($conn_id); return false; } /** * @param string $from * @param string $to * @param bool $ssl * @param string $url * @param string $port * @param string $username * @param string $pw * @param string $subdir * @param string $prefix * @param bool $binary * * @return bool */ protected function GetFile($from, $to, $ssl, $url, $port, $username, $pw, $subdir = '', $prefix = '', $binary = false) { $aktfolder = ''; $this->wasdir = false; if($from === '' || strpos($from,'.') === 0) { $this->fehler[] = 'ungültiger Dateiname '.$from; return false; } if($to === '' || strpos($to,'.') === 0) { $this->fehler[] = 'ungültiger Dateiname '.$to; return false; } if(empty($port)) { $port = 21; } $port = (int)$port; if($ssl) { $conn_id = ftp_ssl_connect($url, $port); } else{ $conn_id = ftp_connect($url, $port); } if(!$conn_id) { $this->fehler[] = 'Verbindung fehlgeschlagen zu '.$url.':'.$port; return false; } $login_result = ftp_login($conn_id, $username, $pw); if($login_result) { ftp_pasv($conn_id, true); if(!empty($subdir) && $subdir !== '/' && $subdir !== '.') { $aktfolder = @ftp_pwd($conn_id); if(!@ftp_chdir($conn_id, $subdir)) { $this->fehler[] = $from." nicht gefunden"; } } $Liste = ftp_nlist($conn_id, '.'); if($Liste !== false) { if(!empty($Liste)) { foreach($Liste as $k => $v) { if($v == $from) { if(@ftp_get($conn_id, $to, $from, ($binary?FTP_BINARY:FTP_ASCII))) { if(file_exists($to)) { if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && $aktfolder != '') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); return true; } if(@ftp_chdir($conn_id, $from)) { @ftp_chdir($conn_id,'..'); $this->wasdir = true; } if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && $aktfolder != '') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); return false; } if(@ftp_chdir($conn_id, $from)) { @ftp_chdir($conn_id,'..'); $this->wasdir = true; } else{ $this->fehler[] = "Fehler beim Herunterladen von " . $from; } if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && $aktfolder != '') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); return false; } } if(!empty($from) && strpos($from, '..') === false && $from[0] !== '.' && @ftp_get($conn_id, $to, $from, ($binary?FTP_BINARY:FTP_ASCII))) { if(file_exists($to)) { if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && $aktfolder != '') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); return true; } if(@ftp_chdir($conn_id, $from)) { @ftp_chdir($conn_id,'..'); $this->wasdir = true; } if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && $aktfolder != '') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); } $this->fehler[] = $from.' nicht gefunden'; } } else{ $this->fehler[] = "Fehler beim Lesen von $url $subdir"; } } else{ $this->fehler[] = 'Login fehlgeschlagen'; } if(!empty($subdir) && $subdir !== '/' && $subdir !== '.' && $aktfolder != '') { @ftp_chdir($conn_id,$aktfolder); } ftp_close($conn_id); return false; } /** * Import a .csv file from payone * all options in $config array are optional. * The default number of days is 5 (DEFAULT_N_DAYS) * and the default file name is stored in * '/tmp/payone.csv' (DEFAULT_FILE) * * The arguments 'PATH' or 'FILE' set the used file, * the keys 'API_DAYS', 'DAYS' or 'TAGE' override the * number of days to look into the past * * @param array $config * @param Application $app * * @return array|string * @throws Exception */ function Import($config, $app) { $this->app = $app; $csv = []; $index = []; $description = []; $config = (array) $config; try { $filename = $this->getFileName($config); } catch (Exception $e) { $filename = ''; } list($ftphost, $ftpport, $ftpuser, $ftppassword, $ftpdebug, $ftpssl, $ftpsubdir, $sftp) = $this->getFtp($config); if($ftphost) { if(empty($filename)){ $filename = date('YmdHis').'.csv'; } //$folder = $this->app->erp->GetTMP(). rtrim($this->app->Conf->WFuserdata,'/').'/payone'; $folder = $this->app->erp->GetTMP().'payone'; if(!file_exists($folder)) { if(!mkdir($folder) && !is_dir($folder)) { $this->app->erp->LogFile($folder.' konnte nicht erstellt werden'); } } $folder = $folder.'/'.$this->app->Conf->WFdbname; if(!file_exists($folder)) { if(!mkdir($folder) && !is_dir($folder)) { $this->app->erp->LogFile($folder.' konnte nicht erstellt werden'); } } $tofile = $folder.'/'.$filename; if($ftphost) { if($sftp) { try { $connection = new PayoneSftpConnection($ftphost, $ftpport); } catch(Exception $e) { $this->fehler[] = $e->getMessage(); $this->app->erp->LogFile($e->getMessage()); return ''; } try { $connection->login($ftpuser, $ftppassword); } catch(Exception $e) { $this->fehler[] = $e->getMessage(); $this->app->erp->LogFile($e->getMessage()); return ''; } $list = $connection->scanFilesystem($ftpsubdir); } else { $list = $this->FTPGetFileList($ftpssl, $ftphost, $ftpport, $ftpuser, $ftppassword, $ftpsubdir); } if(!empty($list)) { foreach($list as $file) { $fullFile = $file; if(!empty($ftpsubdir)) { $fullFile = rtrim($ftpsubdir,'/').'/'.$file; } if($sftp) { try { $getFile = $connection->receiveFile($fullFile, $tofile); } catch (Exception $e) { $this->fehler[] = $e->getMessage(); $this->app->erp->LogFile($e->getMessage()); continue; } } else { $getFile = $this->GetFile($file, $tofile, $ftpssl, $ftphost, $ftpport, $ftpuser, $ftppassword, $ftpsubdir); } if($getFile) { if(!$ftpdebug) { if($sftp){ try { $slash = ''; if(trim($this->subdir) !== '' && substr($this->subdir,-1) !== '/'){ $slash = '/'; } $connection->deleteFile($this->subdir.$slash.$file); } catch (Exception $e) { $this->fehler[] = $e->getMessage(); $this->app->erp->LogFile($e->getMessage()); } } else{ $this->FTPDeleteFile($file, $ftpssl, $ftphost, $ftpport, $ftpuser, $ftppassword, $ftpsubdir); } } $filename = $tofile; break; } } } } } if(!empty($filename)){ $this->openFile($filename); } $completeHeader = []; while(!feof($this->handle)) { $line = $this->readCSVLineAsArray(); if (!$line || (is_array($line) && count($line) <= 1 && empty(reset($line)))) { continue; } /* * Use the first line as header. * Extract some index numbers defined in $requiredHeaders array into $index; * Extract some index numbers defined in $descriptionHeaders array into $description; */ if (empty($index)) { $index = $this->extractIndexFromHeaderLine($line, $this->requiredHeaders); $description = $this->extractIndexFromHeaderLine($line, $this->optionalHeaders); $completeHeader = array_flip($line); $completeHeader = array_change_key_case($completeHeader, CASE_LOWER); try { $this->checkMissingArrayValues($index, $this->requiredHeaders); } catch(Exception $e) { if($ftpdebug) { $this->app->erp->LogFile(['Error '.$e->getMessage().' in File '.$filename, $line]); } throw new Exception($e->getMessage().' in File '.$filename, $e->getCode()); } continue; } try { $data = $this->getDataOfInterest($line, $index); } catch (Exception $e) { if($ftpdebug) { $this->app->erp->LogFile(['Error '.$e->getMessage().' in File '.$filename, $line]); } throw new Exception($e->getMessage().' in File '.$filename, $e->getCode()); } try { $desc = $this->getDataOfInterest($line, $description); } catch (Exception $e) { if($ftpdebug) { $this->app->erp->LogFile(['Error '.$e->getMessage().' in File '.$filename, $line]); } throw new Exception($e->getMessage().' in File '.$filename, $e->getCode()); } /* * The timestamp is in the range, of [today - Number-of-days, today] * so, import this line */ $data = array_merge($data, $desc); foreach($completeHeader as $col => $indHeader) { if(!isset($data[$col]) && !empty($line[$indHeader])) { $data[$col] = $line[$indHeader]; } } $csv[] = $data; } $this->closeFile(); if ($this->getDeleteFlag($config)) { /* * Note: there are no checks about the given file! * At this point the file exists and is readable * other checks aren't performed so this method * may deletes necessary files! */ @unlink($filename); } $header = array_unique(array_values(array_merge($index, $description, array_keys($completeHeader)))); $header = implode(self::COL_DIVIDER, $header); $csv = array_map([$this, 'implodeCSVLine'], $csv); $csv = array_merge([$header], $csv); $csv = implode("\n", $csv); return $csv; } /** * copied and modified from 'ImportKontoauszug' in 'class.erpapi' * used case "stripe" in switch statement * * @param string $csv the csv 'file' to import * @param int $konto the konto id * @param $app * @return array($inserted, $duplicate); * @throws Exception */ public function ImportKontoauszug($csv, $konto, $app) { $this->app = $app; $inserted = 0; $duplicate = 0; if (!is_string($csv)) { $type = gettype($csv); throw new Exception(sprintf( 'Expected csv as string, got \'%s\'', $type )); } // fix values $gebuehr = 0; $gegenkonto = ""; $stamp = time(); $userName = $this->app->User->GetName(); $userName = $this->app->DB->real_escape_string($userName); $csv = $this->explodeCSVLines($csv); if (empty($csv)) { return array($inserted, $duplicate); } $count = count($csv); $csv = array_map([$this, 'explodeCSVLine'], $csv); $header = $this->extractIndexFromHeaderLine($csv[0], $this->requiredHeaders); try { $this->checkMissingArrayValues($header, $this->requiredHeaders); } catch(Exception $e) { $this->app->erp->LogFile(['Error '.$e->getMessage(), $header]); throw new Exception($e->getMessage().' in '.json_encode($header), $e->getCode()); } $completeHeader = array_flip($csv[0]); $completeHeader = array_change_key_case($completeHeader, CASE_LOWER); /* * skip first row -> 'header' line */ for ($i = 1; $i < $count; $i++) { if(count($csv[$i]) <= 1) { continue; } $data = $this->getDataOfInterest($csv[$i], $header); /* * translate / extract */ $betrag = $data['payment']; $vorgang = $data['txid']; $buchung = $data['timestamp']; $waehrung = $data['currency']; foreach( [ 'reference', 'clearingtype', 'clearingsubtype', 'userid', 'customerid', 'email', 'company', 'firstname', 'lastname', 'street', 'zip', 'city', 'country' ] as $col) { if(!empty($data[$col])) { $vorgang .= ' '.$data[$col]; } elseif(!empty($completeHeader[$col]) && !empty($csv[$i][$completeHeader[$col]])) { $vorgang .= ' '.$csv[$i][$completeHeader[$col]]; } } // free some unnecessary memory unset($csv[$i], $data); $buchung = $this->app->DB->real_escape_string( $buchung); $buchung = str_replace('"','', $buchung); $buchung = explode(' ', $buchung); $buchung = $buchung[0]; if(is_numeric($buchung) && (String)(int)$buchung === (String)$buchung) { $buchung = date('Y-m-d', $buchung); } $vorgangUtf8 = iconv('UTF-8', 'UTF-8', $vorgang); if(md5($vorgangUtf8) !== md5($vorgang)){ $vorgang = utf8_encode($vorgang); } $vorgang = $this->app->DB->real_escape_string($vorgang); $vorgang = str_replace('"','',$vorgang); $betrag = $this->app->DB->real_escape_string( $betrag); $waehrung = $this->app->DB->real_escape_string($waehrung); // haben vs. soll list($haben, $soll) = str_replace(',','.', $betrag) > 0 ? array($betrag, "") : array("", $betrag); // hash over some values $pruefsumme = md5(serialize(array($buchung, $vorgang, $soll, $haben, $waehrung))); $sql = "SELECT id FROM kontoauszuege WHERE buchung='$buchung' AND konto='$konto' AND pruefsumme='$pruefsumme' LIMIT 1"; $check = $app->DB->Select($sql); if($check > 0) { $duplicate++; continue; } $soll = str_replace(',','.', $soll); $haben = str_replace(',','.', $haben); $sql = "INSERT INTO kontoauszuege ( konto, buchung, vorgang, soll, haben, gebuehr, waehrung, fertig, bearbeiter, pruefsumme, importgroup, originalbuchung, originalvorgang, originalsoll, originalhaben, originalgebuehr, originalwaehrung, gegenkonto ) VALUE ( '$konto', '$buchung', '$vorgang', '$soll', '$haben', '$gebuehr', '$waehrung', 0, '".$userName."', '$pruefsumme', '$stamp', '$buchung', '$vorgang', '$soll', '$haben', '$gebuehr', '$waehrung', '$gegenkonto')"; $app->DB->Insert($sql); $newid = $app->DB->GetInsertID(); $app->DB->Update("UPDATE kontoauszuege SET sort='$newid' WHERE id='$newid' LIMIT 1"); $inserted++; } return array($inserted, $duplicate); } /** * @param string $filename * * @throws Exception */ private function openFile($filename) { /* * If the open fails, an error of level E_WARNING is generated. */ $handle = @fopen($filename,"r"); if (!$handle) { throw new Exception(sprintf( 'Die Datei \'%s\' kann nicht geöffnet werden!', $filename )); } $this->handle = $handle; } /** * Close File if Handle open */ private function closeFile() { if ($this->handle) { fclose($this->handle); $this->handle = null; } } /** * Read one line, explode and trim all values. * * @return array */ private function readCSVLineAsArray() { $line = fgets($this->handle); $line = trim($line); $line = explode(self::COL_DIVIDER, $line); $line = array_map('trim', $line); $line = array_map([$this, 'trimDoubleQuotes'], $line); return $line; } /** * get the number of days as positive integer, * they can be set via the config keys * 'API_DAYS', 'DAYS' or 'TAGE' * * @param $config * @return int */ private function getFirstDate($config) { $days = self::DEFAULT_N_DAYS; if (array_key_exists('API_DAYS', $config) && is_numeric($config['API_DAYS'])) { $days = $config['API_DAYS']; } elseif (array_key_exists('DAYS', $config) && is_numeric($config['DAYS'])) { $days = $config['DAYS']; } elseif (array_key_exists('TAGE', $config) && is_numeric($config['TAGE'])) { $days = $config['TAGE']; } if (!is_numeric($days)) { $days = self::DEFAULT_N_DAYS; } $days = abs($days); $time = time(); if ($days > 0) { $time = strtotime("-{$days} days", $time); } // var_dump($time, date('Y-m-d', $time), $days); return $time; } /** * @param array $config * * @return array */ private function getFtp($config) { $host = ''; $user = ''; $port = ''; $pw = ''; $debug = ''; $subdir = ''; $ssl = false; $sftp = false; if(!empty($config['SFTP'])) { $sftp = true; } if(!empty($config['FTP_HOST'])) { $host = $config['FTP_HOST']; } if(!empty($config['FTP_USERNAME'])) { $user = $config['FTP_USERNAME']; } if(!empty($config['FTP_PASSWORD'])) { $pw = $config['FTP_PASSWORD']; } if(!empty($config['FTP_PORT'])) { $port = $config['FTP_PORT']; } if(!empty($config['FTP_DEBUG'])) { $debug = $config['FTP_DEBUG']; } if(!empty($config['FTP_SSL'])) { $ssl = $config['FTP_SSL']; } if(!empty($config['FTP_SUBDIR'])) { $subdir = $config['FTP_SUBDIR']; $this->subdir = $subdir; } return [$host, $port, $user, $pw, $debug, $ssl, $subdir, $sftp]; } /** * should we delete the given file after processing? * default is false * * @param $config * @return bool */ private function getDeleteFlag($config) { $delete = array_key_exists('API_DELETE', $config) ? $config['API_DELETE'] : false; $delete = array_key_exists('DELETE', $config) ? $config['DELETE'] : $delete; $delete = array_key_exists('RM', $config) ? $config['RM'] : $delete; return (bool)$delete; } /** * grab the file name, throw an exception * if not present, invalid or not readable * * @param $config * @return string the file name * @throws Exception */ private function getFileName($config) { /* * allow 'PATH' or 'FILE' as key to the .csv file * as fallback if that keys aren't present use * the value behind 'DEFAULT_FILE' */ $file = self::DEFAULT_FILE; if (array_key_exists('PATH', $config)) { $file = (string) $config['PATH']; } if (array_key_exists('FILE', $config)) { $file = (string) $config['FILE']; } if (!$file) { throw new Exception('Keine .csv Datei angegeben'); } if (!$this->endsWith($file, '.csv')) { throw new Exception('Keine .csv Datei angegeben'); } if (strpos($file, '..')) { throw new Exception(sprintf( 'Der Dateiname \'%s\' ist nicht erlaubt.', $file )); } if (!file_exists($file) || !is_file($file)) { throw new Exception( sprintf('Die Datei \'%s\' existiert nicht!', $file )); } if (!is_readable($file)) { throw new Exception(sprintf( 'Die Datei \'%s\' kann nicht gelesen werden!', $file )); } return (string) $file; } /** * @param array $line * * @return string */ private function implodeCSVLine($line) { return implode(self::COL_DIVIDER, $line); } /** * @param array|string $lines * * @return array|false */ private function explodeCSVLines($lines) { if (is_array($lines)) { $lines = implode("\n", $lines); } $lines = preg_split("/(\r\n)+|(\n|\r)+/", $lines); return $lines; } /** * @param string $line * * @return array */ private function explodeCSVLine($line) { $line = str_replace('"','', $line); $line = explode(self::COL_DIVIDER, $line); return $line; } /** * @param string $haystack * @param string $needle * * @return bool */ private function endsWith($haystack, $needle) { $length = strlen($needle); return $length === 0 || (substr($haystack, -$length) === $needle); } /** * Should we append the line? * * compare the date from given line with * the first allowed date * * @see https://stackoverflow.com/a/3847762 for date comparison * @param array|string|int|bool $date * @param int $firstDate timestamp * @return bool */ private function timestampInRangeOfInterest($date, $firstDate) { if (is_array($date)) { $date = $date['timestamp']; } if(!is_numeric($date) && (String)(int)$date !== (String)$date) { $date = strtotime($date); } if (!$date || $date == -1) { /* * Returns a timestamp on success, FALSE otherwise. * Previous to PHP 5.1.0, this function would return -1 on failure. */ return false; } return $date >= $firstDate; } /** * Read the header line and return * an array with index => name pairs like: * * array ( * 2 => 'timestamp', * 4 => 'payment', * 7 => 'currency', * ) * * @param array $line * @param array $required the required values * @return array */ private function extractIndexFromHeaderLine($line, $required) { $tmp = array_flip($line); $tmp = array_change_key_case($tmp, CASE_LOWER); $index = array_flip($required); $index = array_intersect_key($tmp, $index); $index = array_flip($index); ksort($index); return $index; } /** * Remove the double quotes from each value * * @param string $line * @return string */ private function trimDoubleQuotes($line) { return trim($line, '"'); } /** * Throw an exception, is one or more required array values * are missing. * * @param array $array * @param array $required * @throws Exception */ private function checkMissingArrayValues($array, $required) { foreach ($required as $req) { if (!in_array($req, $array)) { throw new Exception(sprintf( 'Could not find column \'%s\' in header line.', $req )); } } } /** * Extract the data of interest. * * $indexes is required as array with * index => name values like: * * array ( * 2 => 'timestamp', * 4 => 'payment', * 7 => 'currency', * ) * * returns an array like: * * array ( * 'timestamp' => '2019-01-02 14:29:31', * 'payment' => '189,90', * 'currency' => 'EUR', * ) * * @param array $line * @param array $indexes * @return array * @throws Exception */ private function getDataOfInterest($line, $indexes) { $tmp = array_intersect_key($line, $indexes); ksort($tmp); /* * Check if an required index is missing. */ $missed = array_diff_key($indexes, $line); if (!empty($missed)) { $cols = count($missed) < 2 ? 'column' : 'columns'; $missed = implode(', ', $missed); throw new Exception(sprintf( 'Could not find %s \'%s\'', $cols, $missed )); } /* * Merge column name with it's value */ $tmp = array_combine($indexes, $tmp); return $tmp; } }