php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #53888 ftruncate() does not work with user-defined stream wrappers
Submitted: 2011-01-31 08:45 UTC Modified: 2011-02-17 01:25 UTC
From: ivan dot enderlin at hoa-project dot net Assigned: cataphract (profile)
Status: Closed Package: Filesystem function related
PHP Version: trunk-SVN-2011-01-31 (SVN) OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: ivan dot enderlin at hoa-project dot net
New email:
PHP Version: OS:

 

 [2011-01-31 08:45 UTC] ivan dot enderlin at hoa-project dot net
Description:
------------
Hey :-),

Seems like ftruncate() does not reconized an user-defined stream (with stream wrapper) as a valid stream. When we use it, it raises the following error: “Can't truncate this stream!”. All the related subject about this error on the Web talks about stream wrappers. Thus, it's seem to be the real problem.

Test script:
---------------
<?php

class StreamWrapper {

    private $_stream     = null;
    private $_streamName = null;
    public  $context     = null;

    public static function realPath ( $path ) {

        return substr($path, 6);
    }

    public function stream_close ( ) {

        if(true === @fclose($this->getStream())) {

            $this->_stream     = null;
            $this->_streamName = null;
        }

        return;
    }

    public function stream_eof ( ) {

        return feof($this->getStream());
    }

    public function stream_flush ( ) {

        return fflush($this->getStream());
    }

    public function stream_lock ( $operation ) {

        return flock($this->getStream(), $operation);
    }

    public function stream_open ( $path, $mode, $options, &$openedPath ) {

        $p = self::realPath($path);

        if(false === $p)
            return false;

        if(null === $this->context)
            $openedPath = fopen(
                $p,
                $mode,
                $options & STREAM_USE_PATH
            );
        else
            $openedPath = fopen(
                $p,
                $mode,
                $options & STREAM_USE_PATH,
                $this->context
            );

        $this->_stream     = $openedPath;
        $this->_streamName = $p;

        return true;
    }

    public function stream_read ( $count ) {

        return fread($this->getStream(), $count);
    }

    public function stream_seek ( $offset, $whence = SEEK_SET ) {

        return fseek($this->getStream(), $offset, $whence);
    }

    public function stream_stat ( ) {

        return fstat($this->getStream());
    }

    public function stream_tell ( ) {

        return ftell($this->getStream());
    }

    public function stream_write ( $data ) {

        return fwrite($this->getStream(), $data);
    }

    public function dir_closedir ( ) {

        if(true === $handle = @closedir($this->getStream())) {

            $this->_stream     = null;
            $this->_streamName = null;
        }

        return $handle;
    }

    public function dir_opendir ( $path, $options ) {

        $p      = self::realPath($path);
        $handle = null;

        if(null === $this->context)
            $handle = @opendir($p);
        else
            $handle = @opendir($p, $this->context);

        if(false === $handle)
            return false;

        $this->_stream     = $handle;
        $this->_streamName = $p;

        return true;
    }

    public function dir_readdir ( ) {

        return readdir($this->getStream());
    }

    public function dir_rewinddir ( ) {

        return rewinddir($this->getStream());
    }

    public function mkdir ( $path, $mode, $options ) {

        if(null === $this->context)
            return mkdir(
                self::realPath($path),
                $mode,
                $options | STREAM_MKDIR_RECURSIVE
            );

        return mkdir(
            self::realPath($path),
            $mode,
            $options | STREAM_MKDIR_RECURSIVE,
            $this->context
        );
    }

    public function rename ( $from, $to ) {

        if(null === $this->context)
            return rename(self::realPath($from), self::realPath($to));

        return rename(self::realPath($from), self::realPath($to), $this->context);
    }

    public function rmdir ( $path, $options ) {

        if(null === $this->context)
            return rmdir(self::realPath($path));
        
        return rmdir(self::realPath($path), $this->context);
    }

    public function unlink ( $path ) {

        if(null === $this->context)
            return unlink(self::realPath($path));

        return unlink(self::realPath($path), $this->context);
    }

    public function url_stat ( $path, $flags ) {

        if(false === $p = self::realPath($path))
            if($flags & STREAM_URL_STAT_QUIET)
                return array(); // Not sure…
            else
                return trigger_error(
                    'Path ' . $path . ' cannot be resolved.',
                    E_WARNING
                );

        if($flags & STREAM_URL_STAT_LINK)
            return @lstat($p);

        return @stat($p);
    }

    protected function getStream ( ) {

        return $this->_stream;
    }

    protected function getStreamName ( ) {

        return $this->_streamName;
    }
}

stream_wrapper_register('bug', 'StreamWrapper');


var_dump($fd = fopen('bug://Test.txt', 'w+'));

var_dump(fwrite($fd,    'Foobar1' . "\n"));
var_dump(fwrite($fd,    'Foobar2' . "\n"));
var_dump(fwrite($fd,    'Foobar3' . "\n"));
var_dump(ftruncate($fd, 3));

var_dump(fclose($fd));

Expected result:
----------------
Output:

resource(7) of type (stream)
int(8)
int(8)
int(8)
bool(true)
bool(true)

Test.txt:
Foo

Actual result:
--------------
Output:

resource(7) of type (stream)
int(8)
int(8)
int(8)
PHP Warning:  ftruncate(): Can't truncate this stream! in /Users/hywan/Development/Hoa/Laboratory/Bug/StreamWrapper.php on line 210

Warning: ftruncate(): Can't truncate this stream! in /Users/hywan/Development/Hoa/Laboratory/Bug/StreamWrapper.php on line 210
bool(false)
bool(true)

Test.txt:
Foobar1
Foobar2
Foobar3

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-02-01 05:33 UTC] aharvey@php.net
-Status: Open +Status: Duplicate
 [2011-02-01 05:33 UTC] aharvey@php.net
Duplicate of request #38025.
 [2011-02-01 08:46 UTC] ivan dot enderlin at hoa-project dot net
But the bug is still open no? And since 2006?
Is this bug affected to someone? Does an explanation of this behavior exist? Please, more details :-).
 [2011-02-01 08:49 UTC] pajoye@php.net
-Status: Duplicate +Status: Open
 [2011-02-01 08:49 UTC] pajoye@php.net
Let keep it open unless the other bug has clear tests cases and similar 
information, which is not the case now.
 [2011-02-01 10:25 UTC] ivan dot enderlin at hoa-project dot net
The bug is open since 2006-07-06, I think that the bug owner is either dead either away :-). Maybe we can focus on this bug which has a detailed example and a detailed description.
What do you think about it :-) ?
 [2011-02-01 13:57 UTC] cataphract@php.net
-Type: Bug +Type: Feature/Change Request
 [2011-02-01 13:57 UTC] cataphract@php.net
This is a feature request because it requires extending the user-land stream wrapper model.

I can take care of it, but I'm more inclined to make it trunk only.
 [2011-02-01 13:57 UTC] cataphract@php.net
-Assigned To: +Assigned To: cataphract
 [2011-02-01 17:52 UTC] ivan dot enderlin at hoa-project dot net
Ok, it's not a bug, it's a missing feature.
So, do you have any workaround to propose me :-p ?

If I can participate to the patch, I'm in.
 [2011-02-17 01:25 UTC] cataphract@php.net
Automatic comment from SVN on behalf of cataphract
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=308410
Log: - Classes that implement stream wrappers can define a method called
  stream_truncate that will respond to truncation, e.g. through ftruncate.
  Closes feature request #53888.
 [2011-02-17 01:25 UTC] cataphract@php.net
-Status: Assigned +Status: Closed
 [2011-02-17 01:25 UTC] cataphract@php.net
Implemented for trunk.
 [2011-02-18 11:45 UTC] ivan dot enderlin at hoa-project dot net
\o/

Thanks.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 16:01:28 2024 UTC