85 lines
2.5 KiB
PHP
85 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace WordPress\ByteStream\ReadStream;
|
|
|
|
use WordPress\ByteStream\ByteStreamException;
|
|
|
|
class FileReadStream extends BaseByteReadStream {
|
|
|
|
protected $file_pointer;
|
|
|
|
public static function from_path( $file_path ) {
|
|
if ( ! file_exists( $file_path ) ) {
|
|
throw new ByteStreamException( esc_html( sprintf( 'File %s does not exist', $file_path ) ) );
|
|
}
|
|
if ( ! is_file( $file_path ) ) {
|
|
throw new ByteStreamException( esc_html( sprintf( '%s is not a file', $file_path ) ) );
|
|
}
|
|
$handle = fopen( $file_path, 'r' );
|
|
if ( ! $handle ) {
|
|
throw new ByteStreamException( esc_html( sprintf( 'Failed to open file %s', $file_path ) ) );
|
|
}
|
|
|
|
return self::from_resource( $handle, filesize( $file_path ) );
|
|
}
|
|
|
|
public static function from_resource( $handle, $expected_length = null ) {
|
|
if ( ! is_resource( $handle ) ) {
|
|
throw new ByteStreamException( 'Invalid file pointer provided' );
|
|
}
|
|
|
|
return new self( $handle, $expected_length );
|
|
}
|
|
|
|
public function __construct( $fp, $expected_length = null ) {
|
|
$this->file_pointer = $fp;
|
|
$this->expected_length = $expected_length;
|
|
}
|
|
|
|
protected function internal_pull( $n ): string {
|
|
$bytes = fread( $this->file_pointer, $n );
|
|
/**
|
|
* Workaround for a streaming bug in WordPress Playground.
|
|
*
|
|
* Without the feof() call, Playground doesn't notice when the stream reaches EOF.
|
|
* The feof() call in internal_reached_end_of_data() somehow does not trigger the
|
|
* EOF event. It must be here, right after fread().
|
|
*
|
|
* @TODO: Improve the streaming support in WordPress Playground.
|
|
*/
|
|
feof( $this->file_pointer );
|
|
if ( false === $bytes ) {
|
|
throw new ByteStreamException( 'Failed to read from file' );
|
|
}
|
|
|
|
return $bytes;
|
|
}
|
|
|
|
protected function seek_outside_of_buffer( int $target_offset ): void {
|
|
$retval = fseek( $this->file_pointer, $target_offset );
|
|
if ( -1 === $retval ) {
|
|
throw new ByteStreamException( 'Failed to seek to offset' );
|
|
}
|
|
|
|
$this->buffer = '';
|
|
$this->offset_in_current_buffer = 0;
|
|
$this->bytes_already_forgotten = $target_offset;
|
|
}
|
|
|
|
public function close_reading(): void {
|
|
if ( $this->is_read_closed ) {
|
|
return;
|
|
}
|
|
$this->is_read_closed = true;
|
|
$this->buffer = '';
|
|
if ( ! fclose( $this->file_pointer ) ) {
|
|
throw new ByteStreamException( 'Failed to close file pointer' );
|
|
}
|
|
$this->file_pointer = null;
|
|
}
|
|
|
|
protected function internal_reached_end_of_data(): bool {
|
|
return ! is_resource( $this->file_pointer ) || feof( $this->file_pointer );
|
|
}
|
|
}
|