PHP Classes

File: src/Stream/MutableFile.php

Recommend this page to a friend!
  Classes of Scott Arciszewski   Halite   src/Stream/MutableFile.php   Download  
File: src/Stream/MutableFile.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Halite
Perform cryptography operations with libsodium
Author: By
Last change: Limit the File API.
For version 2, let's use strict types!
Date: 8 years ago
Size: 4,068 bytes
 

Contents

Class file image Download
<?php
declare(strict_types=1);
namespace
ParagonIE\Halite\Stream;

use \
ParagonIE\Halite\Contract\StreamInterface;
use \
ParagonIE\Halite\Alerts as CryptoException;
use \
ParagonIE\Halite\Util as CryptoUtil;

/**
 * Contrast with ReadOnlyFile: does not prevent race conditions by itself
 */
class MutableFile implements StreamInterface
{
    const
CHUNK = 8192; // PHP's fread() buffer is set to 8192 by default

   
private $closeAfter = false;
    private
$fp;
    private
$pos;
    private
$stat = [];
   
    public function
__construct($file)
    {
        if (
is_string($file)) {
           
$this->fp = \fopen($file, 'wb');
           
$this->closeAfter = true;
           
$this->pos = 0;
           
$this->stat = \fstat($this->fp);
        } elseif (
is_resource($file)) {
           
$this->fp = $file;
           
$this->pos = \ftell($this->fp);
           
$this->stat = \fstat($this->fp);
        } else {
            throw new \
ParagonIE\Halite\Alerts\InvalidType(
               
'Argument 1: Expected a filename or resource'
           
);
        }
    }

    public function
close()
    {
        if (
$this->closeAfter) {
           
$this->closeAfter = false;
            \
fclose($this->fp);
            \
clearstatcache();
        }
    }

    public function
__destruct()
    {
       
$this->close();
    }

   
/**
     * Read from a stream; prevent partial reads
     *
     * @param int $num
     * @return string
     * @throws CryptoException\AccessDenied
     * @throws CryptoException\CannotPerformOperation
     */
   
public function readBytes(int $num, bool $skipTests = false): string
   
{
        if (
$num <= 0) {
            throw new \
Exception('num < 0');
        }
        if ((
$this->pos + $num) > $this->stat['size']) {
            throw new
CryptoException\CannotPerformOperation('Out-of-bounds read');
        }
       
$buf = '';
       
$remaining = $num;
        do {
            if (
$remaining <= 0) {
                break;
            }
           
$read = \fread($this->fp, $remaining);
            if (
$read === false) {
                throw new
CryptoException\FileAccessDenied(
                   
'Could not read from the file'
               
);
            }
           
$buf .= $read;
           
$readSize = CryptoUtil::safeStrlen($read);
           
$this->pos += $readSize;
           
$remaining -= $readSize;
        } while (
$remaining > 0);
        return
$buf;
    }
   
   
/**
     * Write to a stream; prevent partial writes
     *
     * @param string $buf
     * @param int $num (number of bytes)
     * @return int
     * @throws CryptoException\FileAccessDenied
     * @throws CryptoException\CannotPerformOperation
     */
   
public function writeBytes(string $buf, int $num = null): int
   
{
       
$bufSize = CryptoUtil::safeStrlen($buf);
        if (
$num === null || $num > $bufSize) {
           
$num = $bufSize;
        }
        if (
$num < 0) {
            throw new
CryptoException\CannotPerformOperation('num < 0');
        }
       
$remaining = $num;
        do {
            if (
$remaining <= 0) {
                break;
            }
           
$written = \fwrite($this->fp, $buf, $remaining);
            if (
$written === false) {
                throw new
CryptoException\FileAccessDenied(
                   
'Could not write to the file'
               
);
            }
           
$buf = CryptoUtil::safeSubstr($buf, $written, null);
           
$this->pos += $written;
           
$this->stat = \fstat($this->fp);
           
$remaining -= $written;
        } while (
$remaining > 0);
        return
$num;
    }
   
   
/**
     * Set the current cursor position to the desired location
     *
     * @param int $i
     * @return boolean
     * @throws CryptoException\CannotPerformOperation
     */
   
public function reset(int $i = 0): bool
   
{
       
$this->pos = $i;
        if (\
fseek($this->fp, $i, SEEK_SET) === 0) {
            return
true;
        }
        throw new
CryptoException\CannotPerformOperation(
           
'fseek() failed'
       
);
    }
}