public function substr($start, $length)
    {
        $document = $this->getDocument();

        if ($start < 0) {
            $start = max($document['length'] + $start, 0);
        }

        if ($start > $document['length']) {
            return false;
        }

        if ($length < 0) {
            $length = $document['length'] - $start + $length;
            if ($length < 0) {
                return false;
            }
        }

        $chunkSize = $document['chunkSize'];

        $startChunkNumber = floor($start / $chunkSize);

        $chunkIterator = $this->getChunkIterator();

        if (!$chunkIterator->valid()) {
            // invalid iterator state - recreate iterator
            // unable to use `rewind` due to error "Cursors cannot rewind after starting iteration"
            $chunkIterator = $this->getChunkIterator(true);
        }

        if ($chunkIterator->key() > $startChunkNumber) {
            // unable to go back by iterator
            // unable to use `rewind` due to error "Cursors cannot rewind after starting iteration"
            $chunkIterator = $this->getChunkIterator(true);
        }

        $result = '';

        $chunkDataOffset = $start - $startChunkNumber * $chunkSize;
        while ($chunkIterator->valid()) {
            if ($chunkIterator->key() >= $startChunkNumber) {
                $chunk = $chunkIterator->current();
                $data = $chunk['data']->getData();

                $readLength = min($chunkSize - $chunkDataOffset, $length);

                $result .= StringHelper::byteSubstr($data, $chunkDataOffset, $readLength);

                $length -= $readLength;
                if ($length <= 0) {
                    break;
                }

                $chunkDataOffset = 0;
            }

            $chunkIterator->next();
        }

        return $result;
    }
public function substr($start, $length)
    {
        $document = $this->getDocument();

        if ($start < 0) {
            $start = max($document['length'] + $start, 0);
        }

        if ($start > $document['length']) {
            return false;
        }

        if ($length < 0) {
            $length = $document['length'] - $start + $length;
            if ($length < 0) {
                return false;
            }
        }

        $chunkSize = $document['chunkSize'];

        $startChunkNumber = floor($start / $chunkSize);

        $chunkIterator = $this->getChunkIterator();

        if (!$chunkIterator->valid()) {
            // invalid iterator state - recreate iterator
            // unable to use `rewind` due to error "Cursors cannot rewind after starting iteration"
            $chunkIterator = $this->getChunkIterator(true);
        }

        if ($chunkIterator->key() > $startChunkNumber) {
            // unable to go back by iterator
            // unable to use `rewind` due to error "Cursors cannot rewind after starting iteration"
            $chunkIterator = $this->getChunkIterator(true);
        }

        $result = '';

        $chunkDataOffset = $start - $startChunkNumber * $chunkSize;
        while ($chunkIterator->valid()) {
            if ($chunkIterator->key() >= $startChunkNumber) {
                $chunk = $chunkIterator->current();
                $data = $chunk['data']->getData();

                $readLength = min($chunkSize - $chunkDataOffset, $length);

                $result .= StringHelper::byteSubstr($data, $chunkDataOffset, $readLength);

                $length -= $readLength;
                if ($length <= 0) {
                    break;
                }

                $chunkDataOffset = 0;
            }

            $chunkIterator->next();
        }

        return $result;
    }
public function substr ( $ start , $ length ) { $ document = $ this -> getDocument ( ) ; if ( $ start < 0 ) { $ start = max ( $ document [ 'length' ] + $ start , 0 ) ; } if ( $ start > $ document [ 'length' ] ) { return false ; } if ( $ length < 0 ) { $ length = $ document [ 'length' ] - $ start + $ length ; if ( $ length < 0 ) { return false ; } } $ chunkSize = $ document [ 'chunkSize' ] ; $ startChunkNumber = floor ( $ start / $ chunkSize ) ; $ chunkIterator = $ this -> getChunkIterator ( ) ; if ( ! $ chunkIterator -> valid ( ) ) { // invalid iterator state - recreate iterator // unable to use `rewind` due to error "Cursors cannot rewind after starting iteration" $ chunkIterator = $ this -> getChunkIterator ( true ) ; } if ( $ chunkIterator -> key ( ) > $ startChunkNumber ) { // unable to go back by iterator // unable to use `rewind` due to error "Cursors cannot rewind after starting iteration" $ chunkIterator = $ this -> getChunkIterator ( true ) ; } $ result = '' ; $ chunkDataOffset = $ start - $ startChunkNumber * $ chunkSize ; while ( $ chunkIterator -> valid ( ) ) { if ( $ chunkIterator -> key ( ) >= $ startChunkNumber ) { $ chunk = $ chunkIterator -> current ( ) ; $ data = $ chunk [ 'data' ] -> getData ( ) ; $ readLength = min ( $ chunkSize - $ chunkDataOffset , $ length ) ; $ result .= StringHelper :: byteSubstr ( $ data , $ chunkDataOffset , $ readLength ) ; $ length -= $ readLength ; if ( $ length <= 0 ) { break ; } $ chunkDataOffset = 0 ; } $ chunkIterator -> next ( ) ; } return $ result ; }
Return part of a file.
@param int $start reading start position.
If non-negative, the returned string will start at the start'th position in file, counting from zero.
If negative, the returned string will start at the start'th character from the end of file.
@param int $length number of bytes to read.
If given and is positive, the string returned will contain at most length characters beginning from start (depending on the length of file).
If given and is negative, then that many characters will be omitted from the end of file (after the start position has been calculated when a start is negative).
@return string|false the extracted part of file or `false` on failure
Return part of a file .