当我尝试这个时:
$phar = new PharData('./phar.tar', 0, null, Phar::TAR);
$phar->addEmptyDir('test');
file_put_contents('phar://./phar.tar/test/foo.txt', 'bar');
我收到以下错误:
警告:file_put_contents(phar://./phar.tar/test/foo.txt):未能 open stream:无法创建phar'。/ phar.tar',文件扩展名(或 组合)无法识别或目录不存在
我可以使用file_get_contents但shouldn't file_put_contents work too?
为了让事情变得更奇怪,我尝试了@hakre在他的评论中提出的想法并且它有效!
$phar = new PharData('./phar.tar', 0, null, Phar::TAR);
$phar->addEmptyDir('test');
if (file_exists('./phar.phar') !== true)
{
symlink('./phar.tar', './phar.phar');
}
file_put_contents('phar://./phar.phar/test/foo.txt', 'bar');
var_dump(file_get_contents('phar://./phar.tar/test/foo.txt')); // string(3) "bar"
答案 0 :(得分:5)
<强>简介强>
我认为这基本上与您使用Phar::TAR
文件的事实有关,因为
file_put_contents("phar://./test.tar/foo.txt", "hello world");
^
|+---- Note this tar
返回
警告:file_put_contents(phar://./test.tar/foo.txt):无法打开流:无法创建phar'。/ test.tar',文件扩展名(或组合)无法识别或目录无效不存在
虽然
file_put_contents("phar://./test.phar/foo.txt", "hello world"); // Works file
^
|+---- Note This phar
返回
//No Errors
了解问题
如果您查看PHP文档中的detail example,这是过去2 years
的已知问题,给出的示例如下
示例
$p = new PharData(dirname(__FILE__) . '/phartest.zip', 0, 'phartest', Phar::ZIP);
$p->addFromString('testfile.txt', 'this is just some test text');
// This works
echo file_get_contents('phar://phartest.zip/testfile.txt');
// This Fails
file_put_contents('phar://phartest.zip/testfile.txt', 'Thist is text for testfile.txt');
$context = stream_context_create(array(
'phar' => array(
'compress' => Phar::ZIP
)
));
// This Fails
file_put_contents('phar://phartest.zip/testfile.txt', 'Thist is text for testfile.txt', 0, $context);
// This works but only with 'r' readonly mode.
$f = fopen('phar://C:\\Inetpub\\wwwroot\\PACT\\test\\phartest.zip\\testfile.txt', 'r');
工作方式
请勿使用.tar
或.zip
包含您的文件extension
,但请按PHP DOC
我是什么意思?
$context = stream_context_create(array(
'phar' => array(
'compress' => Phar::GZ //set compression
)
));
file_put_contents('phar://sample.phar/somefile.txt', "Sample Data", 0, $context);
^
|= Use phar not tar
<强>建议强>
我真的认为你应该坚持PharData
是可以实现的并且被证明有效。唯一的方法
我必须使用file_put_contents
然后编写自己的包装器并将其注册到stream_wrapper_register
这里是一个简单的概念教授
stream_wrapper_register("alixphar", "AlixPhar");
file_put_contents('alixphar://phar.tar/test/foo.txt', 'hey');
^
|+-- Write with alixphar
echo file_get_contents('alixphar://phar.tar/test/foo.txt'),PHP_EOL;
echo file_get_contents('phar://phar.tar/test/foo.txt'),PHP_EOL;
输出
hey <----- alixphar
hey <----- phar
注意:此类不应在生产中使用...它只是一个示例,并且会使某些测试用例失败
class AlixPhar {
private $pos;
private $stream;
private $types;
private $dir;
private $pharContainer, $pharType, $pharFile, $pharDir = null;
private $fp;
function __construct() {
$this->types = array(
"tar" => Phar::TAR,
"zip" => Phar::ZIP,
"phar" => Phar::PHAR
);
// your phar dir to help avoid using path before the phar file
$this->dir = __DIR__;
}
private function parsePath($path) {
$url = parse_url($path);
$this->pharContainer = $url['host'];
$this->pharType = $this->types[pathinfo($this->pharContainer, PATHINFO_EXTENSION)];
if (strpos($url['path'], ".") !== false) {
list($this->pharDir, $this->pharFile, , ) = array_values(pathinfo($url['path']));
} else {
$this->pharDir = $url['path'];
}
}
public function stream_open($path, $mode, $options, &$opened_path) {
$this->parsePath($path);
$this->stream = new PharData($this->dir . "/" . $this->pharContainer, 0, null, $this->pharType);
if (! empty($this->pharDir))
$this->stream->addEmptyDir($this->pharDir);
if ($mode == "rb") {
$this->fp = fopen("phar://" . $this->pharContainer . "/" . $this->pharDir . "/" . $this->pharFile, $mode);
}
return true;
}
public function stream_write($data) {
$this->pos += strlen($data);
$this->stream->addFromString($this->pharDir . "/" . $this->pharFile, $data);
return $this->pos;
}
public function stream_read($count) {
return fread($this->fp, $count);
}
public function stream_tell() {
return ftell($this->fp);
}
public function stream_eof() {
return feof($this->fp);
}
public function stream_stat() {
return fstat($this->fp);
}
}
答案 1 :(得分:1)
我有一些答案 - 希望这会帮助你。
首先,使用file_put_contents(),我注意到了一些奇怪之处。首先,我所做的是按照您发布的链接示例。我能够添加$ context变量,但仍然有错误。对我来说效果很好的是将文件名更改为phar.phar。也许phar://处理程序无法理解.tar扩展名?
无论如何,这似乎是工作代码 - 但我不推荐
$context = stream_context_create(array('phar' =>
array('compress' => Phar::GZ)),
array('metadata' => array('user' => 'cellog')));
file_put_contents('phar://./phar.phar/test/foo.txt', 'bar', 0, $context);
相反,请使用此功能。
使用我 - 我推荐
$phar = new PharData('./phar.tar', 0, null, Phar::TAR);
$phar->addEmptyDir('test');
$phar->addFile('./bar', 'foo.txt');
如果你真的需要使用file_put_contents(),也许存在一个我们可以帮助的不同问题。谢谢,祝你好运!
答案 2 :(得分:0)
我还有其他一些替代方法,我认为这些方法有点整洁。他们避免使用自定义包装器,符号链接或创建额外文件以使用addFile函数。
选项A
使用与addFromString类似的file_put_contents功能。下面的代码创建了一个TAR存档,向其添加一个文件并对其进行压缩。
$phar = new PharData("./archive.tar", 0, null, Phar::TAR);
$phar->addFromString('out/fileA.txt','The quick brown fox jumped over the lazy dog');
$phar->compress(Phar::GZ); # Creates archive.tar.gz
选项B
如果您出于某种原因确实需要使用file_put_contents。您可以使用它创建PHAR存档,然后重新打开它并将其转换为另一种存档类型。
file_put_contents('phar://archive2.phar/out/fileB.txt', "Colourless green ideas sleep furiously");
$tarphar = new Phar('archive2.phar');
$tar = $tarphar->convertToData(Phar::TAR); # Creates archive2.tar
$zip = $tarphar->convertToData(Phar::ZIP); # Creates archive2.zip
$tgz = $tarphar->convertToData(Phar::TAR, Phar::GZ, '.tar.gz'); # Creates archive2.tar.gz