File: src/Generics/Streams/FileOutputStream.php

Recommend this page to a friend!
  Classes of Maik Greubel  >  PHP Generics  >  src/Generics/Streams/FileOutputStream.php  >  Download  
File: src/Generics/Streams/FileOutputStream.php
Role: Class source
Content type: text/plain
Description: File output stream implementation
Class: PHP Generics
Framework for accessing streams, sockets and logs
Author: By
Last change: Add strict return types & fix socket write bug
Date: 3 years ago
Size: 6,192 bytes
 

Contents

Class file image Download
<?php

/**
 * This file is part of the PHP Generics package.
 *
 * @package Generics
 */
namespace Generics\Streams;

use
Generics\FileExistsException;
use
Generics\NoAccessException;
use
Generics\LockException;
use
Generics\Lockable;
use
Generics\ResetException;
use
Exception;

/**
 * This class provides a file output stream.
 *
 * @author Maik
 */
class FileOutputStream implements OutputStream, Lockable
{

   
/**
     * The file handle
     *
     * @var resource
     */
   
private $handle;

   
/**
     * The absolute file path and name
     *
     * @var string
     */
   
private $fileName;

   
/**
     * Whether resource is locked
     *
     * @var bool
     */
   
private $locked;

   
/**
     * Whether to append
     *
     * @var bool
     */
   
private $append;

   
/**
     * Create a new FileOutputStream
     *
     * @param string $file
     * The absolute (or relative) path to file to write into.
     * @param boolean $append
     * Whether to append the data to an existing file.
     * @throws FileExistsException will be thrown in case of file exists and append is set to false.
     * @throws NoAccessException will be thrown in case of it is not possible to write to file.
     */
   
public function __construct($file, $append = false)
    {
       
$this->open($file, $append);
    }

    private function
open($file, $append)
    {
       
$this->locked = false;
       
       
$mode = "wb";
       
        if (
file_exists($file)) {
            if (!
$append) {
                throw new
FileExistsException("File $file already exists!");
            }
           
            if (!
is_writable($file)) {
                throw new
NoAccessException("Cannot write to file $file");
            }
           
$mode = "ab";
        } else {
            if (!
is_writable(dirname($file))) {
                throw new
NoAccessException("Cannot write to file {file}", array(
                   
'file' => $file
               
));
            }
        }
       
       
$this->handle = fopen($file, $mode);
       
        if (!
$this->ready()) {
            throw new
StreamException("Could not open {file} for writing", array(
               
'file' => $file
           
));
        }
       
       
$this->fileName = $file;
       
$this->append = $append;
    }

   
/**
     * Cleanup (e.g.
     * release lock)
     */
   
public function __destruct()
    {
        try {
            if (
$this->locked) {
               
$this->unlock();
            }
        } catch (\
Generics\GenericsException $ex) {
           
// Do nothing
       
}
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\Stream::ready()
     */
   
public function ready(): bool
   
{
        return
is_resource($this->handle);
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\OutputStream::write()
     */
   
public function write($buffer)
    {
        if (!
$this->ready()) {
            throw new
StreamException("Stream is not open!");
        }
       
        if (
$buffer instanceof InputStream) {
           
$in = clone $buffer;
           
assert($in instanceof InputStream);
            while (
$in->ready()) {
               
$buf = $in->read(1024);
                if (
fwrite($this->handle, $buf) != strlen($buf)) {
                    throw new
StreamException("Could not write memory stream into file");
                }
            }
        } else {
           
$buffer = strval($buffer);
            if (
fwrite($this->handle, $buffer) != strlen($buffer)) {
                throw new
StreamException("Could not write buffer into file");
            }
           
fflush($this->handle);
        }
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\Stream::close()
     */
   
public function close()
    {
        if (
is_resource($this->handle)) {
           
fclose($this->handle);
           
$this->handle = null;
        }
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Countable::count()
     */
   
public function count(): int
   
{
        if (!
$this->ready()) {
            throw new
StreamException("Stream is not open!");
        }
       
        return
ftell($this->handle);
    }

   
/**
     * Retrieve the file path and name
     *
     * @return string
     */
   
public function __toString(): string
   
{
        return
realpath($this->fileName);
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\OutputStream::isWriteable()
     */
   
public function isWriteable(): bool
   
{
        return
$this->ready();
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\OutputStream::flush()
     */
   
public function flush()
    {
        if (!
$this->ready()) {
            throw new
StreamException("Stream is not open!");
        }
       
       
fflush($this->handle);
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Lockable::lock()
     */
   
public function lock()
    {
        if (
$this->locked || flock($this->handle, LOCK_EX) === false) {
            throw new
LockException("Could not acquire lock");
        }
       
$this->locked = true;
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Lockable::unlock()
     */
   
public function unlock()
    {
        if (!
$this->locked || flock($this->handle, LOCK_UN) === false) {
            throw new
LockException("Could not release lock");
        }
       
$this->locked = false;
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Lockable::isLocked()
     */
   
public function isLocked(): bool
   
{
        return
$this->locked;
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\Stream::isOpen()
     */
   
public function isOpen(): bool
   
{
        return
is_resource($this->handle);
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Resettable::reset()
     */
   
public function reset()
    {
        try {
           
$this->close();
           
$this->open($this->fileName, $this->append);
        } catch (
Exception $ex) {
            throw new
ResetException($ex->getMessage(), array(), $ex->getCode(), $ex);
        }
    }
}


For more information send a message to info at phpclasses dot org.