Skip to content

Instantly share code, notes, and snippets.

@finwe
Created February 27, 2013 07:46
Show Gist options
  • Save finwe/5046030 to your computer and use it in GitHub Desktop.
Save finwe/5046030 to your computer and use it in GitHub Desktop.
<?php
/**
* File operations wrapper class
*
* @author Finwe
*/
class File
{
const READ = 1;
const WRITE = 2;
const START = 4;
const END = 8;
const CREATE = 16;
const FAIL_IF_EXISTS = 32;
const TRUNCATE = 64;
const MODE_R = 'r';
const MODE_RPLUS = 'r+';
const MODE_W = 'w';
const MODE_WPLUS = 'w+';
const MODE_A = 'a';
const MODE_APLUS = 'a+';
const MODE_X = 'x';
const MODE_XPLUS = 'x+';
const MODE_C = 'c' ;
const MODE_CPLUS = 'c+';
private $legacyModes = array(
self::MODE_R,
self::MODE_RPLUS,
self::MODE_W,
self::MODE_WPLUS,
self::MODE_A,
self::MODE_APLUS,
self::MODE_X,
self::MODE_XPLUS,
self::MODE_C,
self::MODE_CPLUS
);
private $handler;
/**
* Constructor. Opens a file of given path
*
* @param type $path Path to file
* @param type $mode Mode to open file. Defaults to self::READ | self::WRITE | self::END | self::CREATE
* @param type $useIncludePath
* @param type $context
* @throws InvalidStateException $path does not exist
* @throws InvalidStateException Unable to open file for other reasons
*/
public function __construct($path, $mode = 27, $useIncludePath = false, $context = NULL)
{
if (!self::exists($path)) {
throw new InvalidArgumentException("File $path does not exist");
}
$this->handler = @fopen($path, $this->getMode($mode), $useIncludePath, $context);
if (false === $this->handler) {
$error = error_get_last();
$message = isset($error['message']) ? ': ' . $error['message'] : NULL;
throw new InvalidStateException("Unable to open file $path $message");
}
}
/**
* Static file opening method
*
* @param type $path
* @param type $mode
* @param type $useIncludePath
* @param type $context
* @return \self
*/
public static function open($path, $mode = 27, $useIncludePath = false, $context = NULL)
{
$file = new self;
if ($path) {
$file->open($path, $mode, $useIncludePath, $context);
}
return $file;
}
public function __destruct()
{
$this->close();
}
public function write($data, $length = NULL)
{
return fwrite($this->handler, $data, $length);
}
public function close()
{
if (!$this->handler) {
throw new InvalidStateException('File already closed.');
}
fclose($this->handler);
$this->handler = NULL;
}
/**
* Returns php internal file open mode.
*
* @link http://php.net/manual/en/function.fopen.php
*
* @param mixed $mode
* @return string
*
* @throws InvalidArgumentException on invalid mode or flag combination
*/
private function getMode($mode)
{
$returnMode = NULL;
if (is_int($mode)) {
$read = (0 === $mode | self::READ);
$write = (0 === $mode | self::WRITE);
$start = (0 === $mode | self::START);
$end = (0 === $mode | self::END);
$truncate = (0 === $mode | self::TRUNCATE);
$fail = (0 === $mode | self::FAIL_IF_EXISTS);
$create = (0 === $mode | self::CREATE);
if ($read && $write) {
if ($start) {
if ($truncate && $fail && $create) {
// 'x+' Create and open for reading and writing; otherwise it has the same behavior as 'x'.
return self::MODE_XPLUS;
}
if ($truncate && $create) {
// 'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate the file to zero length.
// If the file does not exist, attempt to create it.
return self::MODE_WPLUS;
}
if ($create) {
// 'c+' Open the file for reading and writing; otherwise it has the same behavior as 'c'.
return self::MODE_CPLUS;
}
// 'r+' Open for reading and writing; place the file pointer at the beginning of the file.
return self::MODE_RPLUS;
} elseif ($end) {
if ($create) {
// 'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does not exist, attempt to create it.
return self::MODE_APLUS;
}
} else {
throw new InvalidArgumentException('No pointer position specified when opening file');
}
} elseif ($read) {
if ($start) {
// 'r' Open for reading only; place the file pointer at the beginning of the file.
return self::MODE_R;
} else {
throw new InvalidArgumentException('Unable to place pointer to end of file when opening for reading only');
}
} elseif ($write) {
if ($start) {
if ($truncate && $create) {
// 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length.
// If the file does not exist, attempt to create it.
return self::MODE_W;
}
if ($fail && $create) {
// 'x' Create and open for writing only; place the file pointer at the beginning of the file.
// If the file already exists, the fopen() call will fail by returning FALSE and generating an error of level E_WARNING.
// If the file does not exist, attempt to create it.
// This is equivalent to specifying O_EXCL|O_CREAT flags for the underlying open(2) system call.
return self::MODE_X;
}
if ($create) {
// 'c' Open the file for writing only. If the file does not exist, it is created.
// If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x').
// The file pointer is positioned on the beginning of the file.
// This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file,
// as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested).
return self::MODE_C;
}
} elseif ($end) {
if ($create) {
// 'a' Open for writing only; place the file pointer at the end of the file. If the file does not exist, attempt to create it.
return self::MODE_A;
}
} else {
throw new InvalidArgumentException('No pointer position specified when opening file');
}
} else {
throw new InvalidArgumentException('No read/write option specified to opened file');
}
throw new InvalidArgumentException('Invalid mode flag combination specified when opening file');
} elseif (in_array($mode, $this->legacyModes)) {
return $mode;
} else {
throw new InvalidArgumentException('Invalid mode given');
}
}
public static function exists($path)
{
return file_exists($path);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment