Is there a way to access a string as a filehandle in php?

前端 未结 5 1999
遥遥无期
遥遥无期 2020-12-17 17:22

I\'m on a server where I\'m limited to PHP 5.2.6 which means str_getcsv is not available to me. I\'m using, instead fgetcsv which requires \"A valid file pointer to a file s

相关标签:
5条回答
  • 2020-12-17 17:58

    You can use stream handles such as php://memory to achieve what you're after. Just open, fwrite, rewind, and you should be able to use fgetcsv.

    0 讨论(0)
  • 2020-12-17 18:02

    Unfortunately, that is not possible. You cannot treat a string as if it's a stream from a file. You would indeed have to first write the string to a file, and then open said file using fopen.

    And now for the obvious part, have you considered upgrading?

    0 讨论(0)
  • 2020-12-17 18:05

    If you take a look in the user notes on the manual page for str_getcsv, you'll find this note from daniel, which proposes this function (quoting) :

    <?php
    if (!function_exists('str_getcsv')) {
        function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") {
            $fiveMBs = 5 * 1024 * 1024;
            $fp = fopen("php://temp/maxmemory:$fiveMBs", 'r+');
            fputs($fp, $input);
            rewind($fp);
    
            $data = fgetcsv($fp, 1000, $delimiter, $enclosure); //  $escape only got added in 5.3.0
    
            fclose($fp);
            return $data;
        }
    }
    ?>
    

    It seems to be doing exactly what you asked for : it uses a stream, which points to a temporary filehandle in memory, to use fgetcsv on it.


    See PHP input/output streams for the documentation about, amongst others, the php://temp stream wrapper.


    Of course, you should test that it works OK for you -- but, at least, this should give you an idea of how to achieve this ;-)

    0 讨论(0)
  • 2020-12-17 18:10

    To answer your general question, yes you can treat a variable as a file stream.

    http://www.php.net/manual/en/function.stream-context-create.php

    The following is a copy and paste from a few different comments on the PHP manual (so I cannot vouch for how production ready it is):

    <?php
    class VariableStream {
        private $position;
        private $varname;
        public function stream_open($path, $mode, $options, &$opened_path) {
            $url = parse_url($path);
            $this->varname = $url["host"];
            $this->position = 0;
            return true;
        }
        public function stream_read($count) {
            $p=&$this->position;
            $ret = substr($GLOBALS[$this->varname], $p, $count);
            $p += strlen($ret);
            return $ret;
        }
        public function stream_write($data){
            $v=&$GLOBALS[$this->varname];
            $l=strlen($data);
            $p=&$this->position;
            $v = substr($v, 0, $p) . $data . substr($v, $p += $l);
            return $l;
        }
        public function stream_tell() {
            return $this->position;
        }
        public function stream_eof() {
            return $this->position >= strlen($GLOBALS[$this->varname]);
        }
        public function stream_seek($offset, $whence) {
            $l=strlen(&$GLOBALS[$this->varname]);
            $p=&$this->position;
            switch ($whence) {
                case SEEK_SET: $newPos = $offset; break;
                case SEEK_CUR: $newPos = $p + $offset; break;
                case SEEK_END: $newPos = $l + $offset; break;
                default: return false;
            }
            $ret = ($newPos >=0 && $newPos <=$l);
            if ($ret) $p=$newPos;
            return $ret;
        }
    }
    
    stream_wrapper_register("var", "VariableStream");
    $csv = "foo,bar\ntest,1,2,3\n";
    
    $row = 1;
    if (($handle = fopen("var://csv", "r")) !== FALSE) {
        while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
            $num = count($data);
            echo "<p> $num fields in line $row: <br /></p>\n";
            $row++;
            for ($c=0; $c < $num; $c++) {
                echo $data[$c] . "<br />\n";
            }
        }
        fclose($handle);
    }
    ?>
    

    Of course, for your particular example, there are simpler stream methods that can be used.

    0 讨论(0)
  • 2020-12-17 18:20

    I'm horrified that no one has answered this solution:

    <?php
    
    $string = "I tried, honestly!";
    $fp     = fopen('data://text/plain,' . $string,'r');
    
    echo stream_get_contents($fp);
    
    #fputcsv($fp, .......);
    
    ?>
    

    And memory hungry perfect solution:

    <?php
    
    class StringStream
    {
        private   $Variable = NULL;
        protected $fp       = 0;
    
        final public function __construct(&$String, $Mode = 'r')
        {
            $this->$Variable = &$String;
    
            switch($Mode)
            {
                case 'r':
                case 'r+':
                    $this->fp = fopen('php://memory','r+');
                    fwrite($this->fp, @strval($String));
                    rewind($this->fp);
                    break;
    
                case 'a':
                case 'a+':
                    $this->fp = fopen('php://memory','r+');
                    fwrite($this->fp, @strval($String));
                    break;
    
                default:
                    $this->fp = fopen('php://memory',$Mode);
            }
        }
    
        final public function flush()
        {
            # Update variable
            $this->Variable = stream_get_contents($this->fp);
        }
    
        final public function __destruct()
        {
            # Update variable on destruction;
            $this->Variable = stream_get_contents($this->fp);
        }
    
        public function __get($name)
        {
            switch($name)
            {
                case 'fp': return $fp;
                default:   trigger error('Undefined property: ('.$name.').');
            }
    
            return NULL;
        }
    }
    
    $string = 'Some bad-ass string';
    $stream = new StringStream($string);
    
    echo stream_get_contents($stream->fp);
    #fputcsv($stream->fp, .......);
    

    ?>

    0 讨论(0)
提交回复
热议问题