处理 user_abort 后 DOMDocument->save() 失败
DOMDocument->save() fails after user_abort is handled
在 PHP
中,可以 register shutdown functions,在我的场景中明确调用了它(但有时会被忽略),见下文。
PHP/libxml 支持 DOMDocument class in PHP does not play along well w/ my registered shutdown functions, if I want to call ->save()
(->saveXML()
works fine) after user abort (e.g. from registered shutdown function
or a class instance destructor
). Related is also the PHP connection handling.
让例子说话:
PHP版本:
php --version
PHP 7.1.4 (cli) (built: Apr 25 2017 09:48:36) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
为了重现 user_abort 我正在 运行 宁 php 通过 python2.7 run.py
:
import subprocess
cmd = ["/usr/bin/php", "./user_aborted.php"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
# As this process exists here and the user_aborted.php
# has sleeps/blocks in for-cycle thus simulating a user-abort
# for the php subprocess.
php 脚本 user_aborted.php
尝试在关闭函数 XML 中保存 :
<?php
ignore_user_abort(false);
libxml_use_internal_errors(true);
$xml = new DOMDocument();
$xml_track = $xml->createElement( "Track", "Highway Blues" );
$xml->appendChild($xml_track);
function shutdown() {
global $xml;
$out_as_str = $xml->saveXML();
fwrite(STDERR, "\nout_as_str: " . var_export($out_as_str, true) . "\n");
$out_as_file = $xml->save('out.xml');
fwrite(STDERR, "\nout_as_file: >" . var_export($out_as_file, true) . "<\n");
fwrite(STDERR, "\nerrors: \n" . var_export(libxml_get_errors(), true) . "\n");
}
register_shutdown_function('shutdown');
$i = 2;
while ($i > 0) {
fwrite(STDERR, "\n PID: " . getmypid() . " aborted: " . connection_aborted());
echo("\nmaking some output on stdout"); // so user_abort will be checked
sleep(1);
$i--;
}
现在,如果我 运行 此脚本 w/o 用户中止(只需调用 PHP):
php user_aborted.php
XML 得到正确保存。
但是 当通过 python2.7
调用它时(模拟用户通过退出父进程中止),python2.7 run.py
最奇怪的事情发生了:
out_as_str
值很好,看起来XML我想要的
- 但是文件
out.xml
是一个空文件
- 另外
libxml_get_errors
报告 FLUSH 问题
带有 python 的输出看起来是:
python2.7 run.py
PID: 16863 aborted: 0
out_as_str: '<?xml version="1.0"?>
<Track>Highway Blues</Track>
'
out_as_file: >false<
errors:
array (
0 =>
LibXMLError::__set_state(array(
'level' => 2,
'code' => 1545,
'column' => 0,
'message' => 'flush error',
'file' => '',
'line' => 0,
))
)
很抱歉 post,但我整天都在查看 PHP/libxml2 代码 w/o 是否成功。 :/
原因:
事实证明这是由于修复了之前的错误。
链接:
- previous PHP bug ticket which fix introduced the deffect
- commit that introduces the deffect (GitHub)
链接的 php_libxml_streams_IO_write
函数是 writecallback
(设置 in ext/libxml/libxml.c) for the buffer of the docp
object, which is handed over for the libxml
call on ext/dom/document.c. Ending up in libxml xmlIO.c,其中缓冲区是 NULL
,因此为 ->save(*)
提供的文件不会得到写了。
解决方法:
使用->saveXML()
获取字符串中的XML表示并使用"hand":
使用file_put_contents(*)
编写
$xml_as_str = $xml->saveXML();
file_put_contents('/tmp/my.xml', $xml_as_str);
在 PHP
中,可以 register shutdown functions,在我的场景中明确调用了它(但有时会被忽略),见下文。
PHP/libxml 支持 DOMDocument class in PHP does not play along well w/ my registered shutdown functions, if I want to call ->save()
(->saveXML()
works fine) after user abort (e.g. from registered shutdown function
or a class instance destructor
). Related is also the PHP connection handling.
让例子说话:
PHP版本:
php --version
PHP 7.1.4 (cli) (built: Apr 25 2017 09:48:36) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
为了重现 user_abort 我正在 运行 宁 php 通过 python2.7 run.py
:
import subprocess
cmd = ["/usr/bin/php", "./user_aborted.php"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
# As this process exists here and the user_aborted.php
# has sleeps/blocks in for-cycle thus simulating a user-abort
# for the php subprocess.
php 脚本 user_aborted.php
尝试在关闭函数 XML 中保存 :
<?php
ignore_user_abort(false);
libxml_use_internal_errors(true);
$xml = new DOMDocument();
$xml_track = $xml->createElement( "Track", "Highway Blues" );
$xml->appendChild($xml_track);
function shutdown() {
global $xml;
$out_as_str = $xml->saveXML();
fwrite(STDERR, "\nout_as_str: " . var_export($out_as_str, true) . "\n");
$out_as_file = $xml->save('out.xml');
fwrite(STDERR, "\nout_as_file: >" . var_export($out_as_file, true) . "<\n");
fwrite(STDERR, "\nerrors: \n" . var_export(libxml_get_errors(), true) . "\n");
}
register_shutdown_function('shutdown');
$i = 2;
while ($i > 0) {
fwrite(STDERR, "\n PID: " . getmypid() . " aborted: " . connection_aborted());
echo("\nmaking some output on stdout"); // so user_abort will be checked
sleep(1);
$i--;
}
现在,如果我 运行 此脚本 w/o 用户中止(只需调用 PHP):
php user_aborted.php
XML 得到正确保存。
但是 当通过 python2.7
调用它时(模拟用户通过退出父进程中止),python2.7 run.py
最奇怪的事情发生了:
out_as_str
值很好,看起来XML我想要的- 但是文件
out.xml
是一个空文件 - 另外
libxml_get_errors
报告 FLUSH 问题
带有 python 的输出看起来是: python2.7 run.py
PID: 16863 aborted: 0
out_as_str: '<?xml version="1.0"?>
<Track>Highway Blues</Track>
'
out_as_file: >false<
errors:
array (
0 =>
LibXMLError::__set_state(array(
'level' => 2,
'code' => 1545,
'column' => 0,
'message' => 'flush error',
'file' => '',
'line' => 0,
))
)
很抱歉 post,但我整天都在查看 PHP/libxml2 代码 w/o 是否成功。 :/
原因:
事实证明这是由于修复了之前的错误。
链接:
- previous PHP bug ticket which fix introduced the deffect
- commit that introduces the deffect (GitHub)
链接的 php_libxml_streams_IO_write
函数是 writecallback
(设置 in ext/libxml/libxml.c) for the buffer of the docp
object, which is handed over for the libxml
call on ext/dom/document.c. Ending up in libxml xmlIO.c,其中缓冲区是 NULL
,因此为 ->save(*)
提供的文件不会得到写了。
解决方法:
使用->saveXML()
获取字符串中的XML表示并使用"hand":
file_put_contents(*)
编写
$xml_as_str = $xml->saveXML();
file_put_contents('/tmp/my.xml', $xml_as_str);