我所在的服务器只支持 PHP 5.2.6,因此无法使用 str_getcsv 函数,而需要使用 fgetcsv 函数。但是,该函数要求操作的文件必须是通过 fopen()、popen() 或 fsockopen() 成功打开的有效文件指针。
我的问题是:是否有一种方法可以将字符串作为文件指针来访问?
另一种选择是将字符串写入文本文件中,然后通过 fopen()
访问它,再使用 fgetcsv
函数进行操作,但我希望能够像 perl 语言那样直接操作。
我所在的服务器只支持 PHP 5.2.6,因此无法使用 str_getcsv 函数,而需要使用 fgetcsv 函数。但是,该函数要求操作的文件必须是通过 fopen()、popen() 或 fsockopen() 成功打开的有效文件指针。
我的问题是:是否有一种方法可以将字符串作为文件指针来访问?
另一种选择是将字符串写入文本文件中,然后通过 fopen()
访问它,再使用 fgetcsv
函数进行操作,但我希望能够像 perl 语言那样直接操作。
如果你查看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
流包装器。
当然,您应该测试它是否适用于您--但至少,这应该给您一个实现此目的的想法 ;-)
我很震惊没有人回答这个解决方案:
<?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, .......);
?>
data://
方法中,提供的 $string
在被输入到 data://
之前应该进行百分号编码。请参阅 https://www.php.net/manual/en/wrappers.data.php#100979。 - Jaime Hablutzelhttp://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);
}
?>
很遗憾,这是不可能的。您不能将字符串视为文件流。您确实需要先将字符串写入文件,然后使用fopen
打开该文件。
现在显而易见的是,您考虑过升级吗?
php://memory
-php://temp
的唯一优点是当文件超过指定大小时,它会写入磁盘;如果你的文件大小在其下,它将完全保存在内存中。 - Erikfopen(“php://output”,'r+');
被使用,但是您的解决方案更好,因为它不会干扰主输出。 - Liam