12

我在一个仅限于 PHP 5.2.6 的服务器上,这意味着我无法使用 str_getcsv。我使用的是 fgetcsv,它需要“指向由 fopen()、popen() 或 fsockopen() 成功打开的文件的有效文件指针”。操作。

我的问题是:有没有办法将字符串作为文件句柄访问?

我的另一个选择是将字符串写入文本文件,然后通过访问它fopen()然后使用fgetcsv,但我希望有一种方法可以直接执行此操作,例如在 perl 中。

4

5 回答 5

23

如果您查看手册页上的用户注释str_getcsv,您会发现来自 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 输入/输出流。php://temp


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

于 2010-02-16T21:56:22.370 回答
8

我很震惊没有人回答这个解决方案:

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

?>

于 2014-01-30T07:33:49.300 回答
6

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

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

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

于 2010-02-16T22:05:52.447 回答
1

您可以使用诸如php://memory之类的流句柄来实现您所追求的。只需打开、fwrite、倒带,您应该可以使用 fgetcsv。

于 2010-02-16T22:00:28.510 回答
-3

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

现在很明显,您是否考虑过升级?

于 2010-02-16T21:52:17.183 回答