list = collect(); $this->sending = NULL; $this->file_pos = 0; $this->f = NULL; } public function __get($key) { switch ($key) { case 'fd': return is_resource($this->f); case 'file_count': return $this->list ->filter(function($item) { return $item->isType(self::IS_FILE); }) ->count(); case 'file_size': return $this->list ->filter(function($item) { return $item->isType(self::IS_FILE); }) ->sum(function($item) { return $item->file_size; }); case 'filepos': return $this->file_pos; case 'mail_count': return $this->list ->filter(function($item) { return $item->isType(self::IS_ARC|self::IS_PKT); }) ->count(); case 'mail_size': return $this->list ->filter(function($item) { return $item->isType(self::IS_ARC|self::IS_PKT); }) ->sum(function($item) { return $item->file_size; }); case 'sendas': return $this->sending ? $this->sending->{$key} : NULL; case 'name': case 'mtime': case 'size': return $this->sending ? $this->sending->{'file_'.$key} : NULL; case 'total_sent': return $this->list ->filter(function($item) { return ($item->action & self::I_SEND) && $item->sent === TRUE; }) ->count(); case 'total_sent_bytes': return $this->list ->filter(function($item) { return ($item->action & self::I_SEND) && $item->sent === TRUE; }) ->sum(function($item) { return $item->file_size; }); case 'total_count': return $this->list ->filter(function($item) { return ($item->action & self::I_SEND) && $item->sent === FALSE; }) ->count(); case 'total_size': return $this->list ->sum(function($item) { return $item->file_size; }); default: throw new Exception('Unknown key: '.$key); } } /** * Add a file to the list of files to send * * @param string $file * @throws Exception */ public function add(string $file): void { Log::debug(sprintf('%s: + Start [%s]',__METHOD__,$file)); try { $this->list->push(new Item($file,self::I_SEND)); } catch (FileNotFoundException) { Log::error(sprintf('%s: ! Item [%s] doesnt exist',__METHOD__,$file)); return; } catch (UnreadableFileException) { Log::error(sprintf('%s: ! Item [%s] cannot be read',__METHOD__,$file)); return; // Uncaught, rethrow the error } catch (Exception $e) { throw new Exception($e->getMessage()); } } /** * Close the file descriptor of the file we are sending * * @param bool $successful * @throws Exception */ public function close(bool $successful): void { if (! $this->f) throw new Exception('No file to close'); if ($successful) { $this->sending->sent = TRUE; $end = time()-$this->start; Log::debug(sprintf('%s: - Closing [%s], sent in [%d]',__METHOD__,$this->sending->file_name,$end)); } fclose($this->f); $this->sending = NULL; $this->file_pos = 0; $this->f = NULL; } /** * Check if we are at the end of the file * * @return bool */ public function feof(): bool { return feof($this->f); } /** * Open a file for sending * * @return bool * @throws Exception */ public function open(): bool { Log::debug(sprintf('%s: + Start',__METHOD__)); $this->sending = $this->list ->filter(function($item) { return ($item->action & self::I_SEND) && $item->sent === FALSE; }) ->first(); if (! $this->sending) throw new Exception('No files to open'); $this->file_pos = 0; $this->start = time(); $this->f = fopen($this->sending->file_name,'rb'); if (! $this->f) { Log::error(sprintf('%s: ! Unable to open file [%s] for reading',__METHOD__,$this->sending->file_name)); return FALSE; } Log::info(sprintf('%s: = End - File [%s] opened with size [%d]',__METHOD__,$this->sending->file_name,$this->sending->file_size)); return TRUE; } /** * Read bytes of the sending file * * @param int $length * @return string|null * @throws UnreadableFileException * @throws Exception */ public function read(int $length): ?string { if (! $this->f) throw new Exception('No file open for read'); $data = fread($this->f,$length); $this->file_pos += strlen($data); Log::debug(sprintf('%s: - Read [%d] bytes, file pos now [%d]',__METHOD__,strlen($data),$this->file_pos)); if ($data === FALSE) throw new UnreadableFileException('Error reading file: '.$this->sending->file_name); return $data; } /** * Seek to a specific position of our file * * @param int $pos * @return bool * @throws Exception */ public function seek(int $pos): bool { if (! $this->f) throw new Exception('No file open for seek'); $rc = (fseek($this->f,$pos,SEEK_SET) === 0); if ($rc) $this->file_pos = $pos; Log::debug(sprintf('%s: - Seeked to [%d]',__METHOD__,$this->file_pos)); return $rc; } }