解决方案:使用一个具有唯一文件名的临时文件,在多次跳转和爬入PHP最脏的角落后,我将问题重新表述为:
如何诱使PHP返回TRUE
对于file_exists( $file )
?
因为核心中的代码
file_exists( apply_filters( \'comments_template\', $template ) )
然后问题得到了更快的解决:
$template = tempnam( __DIR__, \'\' );
就这样。也许使用
wp_upload_dir()
而是:
$uploads = wp_upload_dir();
$template = tempname( $uploads[\'basedir\'], \'\' );
另一种选择可能是使用
get_temp_dir()
哪个包裹
WP_TEMP_DIR
. 提示:奇怪的是
/tmp/
因此,文件将在重新启动之间保留,这
/var/tmp/
将可以在末尾进行简单的字符串比较,检查返回值,然后在需要时进行修复,但本例中没有:
$template = tempname( get_temp_dir(), \'\' )
现在,要快速测试没有内容的临时文件是否引发错误,请执行以下操作:
<?php
error_reporting( E_ALL );
$template = tempnam( __DIR__, \'\' );
var_dump( $template );
require $template;
以及:
No Errors → 工作
EDIT: 像@toscho 在评论中指出better 方法:
$template = tempnam( trailingslashit( untrailingslashit( sys_get_temp_dir() ) ), \'comments.php\' );
注:根据
a users note on php.net docs, 这个
sys_get_temp_dir()
系统之间的行为不同。因此,结果将删除尾部斜杠,然后再次添加。作为核心bug
#22267 已修复,现在也可以在Win/IIS服务器上使用。
重构函数(未测试):
function engineCommentsTemplate( $engine )
{
$template = null;
$tmplGetter = function( $original ) use( &$template ) {
$template = $original;
return tempnam(
trailingslashit( untrailingslashit( sys_get_temp_dir() ) ),
\'comments.php\'
);
};
add_filter( \'comments_template\', $tmplGetter, PHP_INT_MAX );
comments_template();
remove_filter( \'comments_template\', $tmplGetter, PHP_INT_MAX );
if ( is_file( $template ) && is_readable( $template ) ) {
return $engine->render( $template );
}
return \'\';
}
奖金编号1:
tmpfile()
将返回
NULL
. 是的,真的。
奖金编号2:file_exists( __DIR__ )
将返回TRUE
. 是的,真的……万一你忘了。
这会导致WP core中出现实际错误
为了帮助其他人进入探索者模式并找到那些(对未记录的片段来说很糟糕),我将快速总结一下我所做的尝试:
尝试1:内存中的临时文件我的第一次尝试是使用php://temp
. 从PHP文档:
两者之间的唯一区别是php://memory
将始终将其数据存储在内存中php://temp
一旦存储的数据量达到预定义的限制(默认值为2 MB),将使用临时文件。此临时文件的位置的确定方式与sys_get_temp_dir()
作用
代码:
$handle = fopen( \'php://temp\', \'r+\' );
fwrite( $handle, \'foo\' );
rewind( $handle );
var_dump( file_exist( stream_get_contents( $handle, 5 ) );
发现:不,不起作用。
尝试2:使用临时文件tmpfile()
, 那为什么不用它呢?!
var_dump( file_exists( tmpfile() ) );
// boolean FALSE
是的,这条捷径就是这么回事。
class TemplateStreamWrapper
{
public $context;
public function stream_open( $path, $mode, $options, &$opened )
{
// return boolean
}
}
stream_wrapper_register( \'vt://comments\', \'TemplateStreamWrapper\' );
// … etc. …
再次返回
NULL
在…上
file_exists()
.
用PHP 5.6.20测试