blob: b68de63eed1d002a271fb58732b06017bcb7ad63 [file] [log] [blame]
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Apache\Avro\IO;
use Apache\Avro\AvroIO;
/**
* AvroIO wrapper for PHP file access functions
* @package Avro
*/
class AvroFile extends AvroIO
{
/**
* @var string fopen read mode value. Used internally.
*/
public const FOPEN_READ_MODE = 'rb';
/**
* @var string fopen write mode value. Used internally.
*/
public const FOPEN_WRITE_MODE = 'wb';
/**
* @var string
*/
private $file_path;
/**
* @var resource file handle for AvroFile instance
*/
private $file_handle;
public function __construct($file_path, $mode = self::READ_MODE)
{
/**
* XXX: should we check for file existence (in case of reading)
* or anything else about the provided file_path argument?
*/
$this->file_path = $file_path;
switch ($mode) {
case self::WRITE_MODE:
$this->file_handle = fopen($this->file_path, self::FOPEN_WRITE_MODE);
if (false == $this->file_handle) {
throw new AvroIOException('Could not open file for writing');
}
break;
case self::READ_MODE:
$this->file_handle = fopen($this->file_path, self::FOPEN_READ_MODE);
if (false == $this->file_handle) {
throw new AvroIOException('Could not open file for reading');
}
break;
default:
throw new AvroIOException(
sprintf(
"Only modes '%s' and '%s' allowed. You provided '%s'.",
self::READ_MODE,
self::WRITE_MODE,
$mode
)
);
}
}
/**
* @returns int count of bytes written
* @throws AvroIOException if write failed.
*/
public function write($str)
{
$len = fwrite($this->file_handle, $str);
if (false === $len) {
throw new AvroIOException(sprintf('Could not write to file'));
}
return $len;
}
/**
* @returns int current position within the file
* @throws AvroIOException if tell failed.
*/
public function tell()
{
$position = ftell($this->file_handle);
if (false === $position) {
throw new AvroIOException('Could not execute tell on reader');
}
return $position;
}
/**
* Closes the file.
* @returns boolean true if successful.
* @throws AvroIOException if there was an error closing the file.
*/
public function close()
{
$res = fclose($this->file_handle);
if (false === $res) {
throw new AvroIOException('Error closing file.');
}
return $res;
}
/**
* @returns boolean true if the pointer is at the end of the file,
* and false otherwise.
* @see AvroIO::isEof() as behavior differs from feof()
*/
public function isEof()
{
$this->read(1);
if (feof($this->file_handle)) {
return true;
}
$this->seek(-1, self::SEEK_CUR);
return false;
}
/**
* @param int $len count of bytes to read.
* @returns string bytes read
* @throws AvroIOException if length value is negative or if the read failed
*/
public function read($len)
{
if (0 > $len) {
throw new AvroIOException(
sprintf("Invalid length value passed to read: %d", $len)
);
}
if (0 == $len) {
return '';
}
$bytes = fread($this->file_handle, $len);
if (false === $bytes) {
throw new AvroIOException('Could not read from file');
}
return $bytes;
}
/**
* @param int $offset
* @param int $whence
* @returns boolean true upon success
* @throws AvroIOException if seek failed.
* @see AvroIO::seek()
*/
public function seek($offset, $whence = SEEK_SET): bool
{
$res = fseek($this->file_handle, $offset, $whence);
// Note: does not catch seeking beyond end of file
if (-1 === $res) {
throw new AvroIOException(
sprintf(
"Could not execute seek (offset = %d, whence = %d)",
$offset,
$whence
)
);
}
return true;
}
/**
* @returns boolean true if the flush was successful.
* @throws AvroIOException if there was an error flushing the file.
*/
public function flush()
{
$res = fflush($this->file_handle);
if (false === $res) {
throw new AvroIOException('Could not flush file.');
}
return true;
}
}