代码之家  ›  专栏  ›  技术社区  ›  Erik

有没有一种方法可以在PHP中以文件句柄的形式访问字符串?

  •  9
  • Erik  · 技术社区  · 14 年前

    我在一个服务器上,我被限制在php 5.2.6,这意味着str_getcsv对我不可用。我使用的是fgetcsv,而fgetcsv需要“一个有效的文件指针指向一个通过fopen()、popen()或fsockopen()成功打开的文件”才能操作。

    我的问题是:有没有一种方法可以将字符串作为文件句柄访问?

    我的另一个选择是将字符串写入文本文件,然后通过 fopen() 然后使用 fgetcsv 但是我希望有一种方法可以直接做到这一点,就像在Perl中一样。

    5 回复  |  直到 11 年前
        1
  •  20
  •   Pascal MARTIN    14 年前

    如果您查看手册页上的用户说明 str_getcsv 你会发现 this note from daniel ,提出了这个函数 (引证) 以下内容:

    <?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;
        }
    }
    ?>
    

    它似乎正按照您的要求执行:它使用指向内存中临时文件句柄的流来使用 fgetcsv 在上面。


    PHP input/output streams 除其他文件外,关于 php://temp 流包装器。


    当然,您应该测试它是否适合您——但是,至少,这应该让您了解如何实现这一点;-)

        2
  •  7
  •   mAsT3RpEE    11 年前

    我很震惊没有人回答这个问题:

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

    以及内存不足的完美解决方案:

    <?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, .......);
    

    ?gt;

        3
  •  6
  •   Matthew    14 年前

    要回答一般问题,可以将变量视为文件流。

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

    下面是从PHP手册上的几个不同注释中复制粘贴的内容(因此我不能保证它是如何准备好生产的):

    <?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);
    }
    ?>
    

    当然,对于您的特定示例,可以使用更简单的流方法。

        4
  •  0
  •   Eric Butera    14 年前

    您可以使用流句柄,例如 php://memory 去实现你想要的。只需打开、写入、倒带,就可以使用fgetcsv。

        5
  •  -3
  •   Aistina    14 年前

    不幸的是,这是不可能的。不能将字符串视为来自文件的流。您必须首先将字符串写入一个文件,然后使用 fopen .

    现在显然,你考虑过升级吗?