return $this->flush(); } return false; } /** * Flush the data from the stream to another stream * * If no target stream is being passed and you have cached data that is not yet stored into the underlying storage, * you should do so now * * @param resource|null $stream The stream resource to flush the data too * @param int $length The total bytes to flush, if -1 the stream will be flushed until eof. The limit should * lie within the total size of the stream. * @return boolean Should return TRUE if the cached data was successfully stored (or if there was no data to store), * or FALSE if the data could not be stored. */ public function flush($stream = null, $length = -1) { $result = false; if($this->getType() == 'memory') { if(!is_resource($stream)) { if($path = $this->getPath() && $this->isWritable() && !$this->_synchronised) { try { $handle = @fopen($path, 'w'); } catch (Exception $e) { $handle = false; } if ($handle === false) { throw new RuntimeException(sprintf( 'File "%s" cannot be opened with mode "%s"', $path, $this->getMode() )); } //Flush the content to the underlying storage $result = fwrite($handle, $this->_resource); } } //Flush the content to another stream else $result = fwrite($stream, $this->_resource); } return $result; } /** * Truncate to given size * * @param int $size The new size * @return bool Returns TRUE on success or FALSE on failure. */ public function truncate($size) { if($this->isWritable()) { if($this->getType() == 'memory') { if ($this->_length > $size) { $this->_resource = substr($this->_resource, 0, $size); } else { $this->_resource = str_pad($this->_resource, $size, "\0", STR_PAD_RIGHT); } } else return parent::truncate($size); return true; } return false; } /** * Get the stream type * * @return string The stream type */ public function getType() { if($this->_type == null) { $this->_type = parse_url($this->_path, PHP_URL_HOST); } return $this->_type; } /** * Get the stream path * * @return string he URI/filename associated with this stream */ public function getPath() { if($this->getType() == 'memory') { $this->_path = parse_url($this->_path, PHP_URL_PATH); } if($this->getType() == 'temp') { if(!$this->getResource()) { $this->_path = $this->getTemporaryFile(); } } return parent::getPath(); } /** * Get the stream mode * * @param bool $include_flags If false strip binary/text flags from mode. Default TRUE. * @return string */ public function getMode($include_flags = true) { //Temp streams are always writable if($this->getType() == 'temp') { $this->_mode = 'w+b'; } return parent::getMode($include_flags); } /** * Retrieve information about the resource pointed to by the stream * * @param boolean $link For resources with the ability to link to other resource (such as an HTTP Location: forward, * or a filesystem symlink). This flag specified that only information about the link itself * should be returned, not the resource pointed to by the link. This flag is set in response * to calls to lstat(), is_link(), or filetype(). * @throws \BadMethodCallException if info is not supported. * @return array See http://php.net/stat */ public function getInfo($link = false) { if($this->getType() == 'memory') { $info = array('dev' => 0, 'ino' => 0, 'mode' => 0, 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'size' => $this->_length, 'atime' => time(), 'mtime' => time(), 'ctime' => time(), 'blksize' => -1, 'blocks' => -1); } else $info = parent::getInfo($link); return $info; } /** * Creates a file with a unique file name * * @param string|null $directory Uses the result of getTemporaryDirectory() by default * @return string File path */ public function getTemporaryFile($directory = null) { if ($directory === null) { $directory = $this->getTemporaryDirectory(); } $name = str_replace('.', '', uniqid('buffer', true)); $path = $directory.'/'.$name; touch($path); return $path; } /** * Returns a directory path for temporary files * * @return string Folder path */ public function getTemporaryDirectory() { return sys_get_temp_dir(); } /** * Check if the stream is seekable * * @return bool Returns TRUE on success or FALSE on failure. */ public function isSeekable() { //Memory streams are always seekable if($this->getType() == 'memory') { return true; } return parent::isSeekable(); } /** * Reads all data from the stream into a string, from the beginning to end. * * This method MUST attempt to seek to the beginning of the stream before reading data and read the stream until * the end is reached. The file pointer should stay at it's original position. * * Warning: This could attempt to load a large amount of data into memory. * * @return string */ public function toString() { if($this->getType() == 'memory') { return $this->_resource; } return parent::toString(); } }