为什么DOMDocument :: schemaValidate()在相同的XML和XSD文件上的执行时间有时会比平时高得多?

时间:2015-09-11 15:36:33

标签: php xml xsd domdocument execution-time

默认类方法有时会失败,有时,即使传递给方法的参数相同,通常只需要几分之一秒。

  

超过30秒的最大执行时间    script_path   在线 script_line_number

在那一行中:

$result = $DOMDocument -> schemaValidate($schemaPath);

$ DOMDocument总是一样的。它只引用具有ID atrtibutes的相同XML的部分。除了Algorith和xmlns之外,它没有任何类似属性的URL,它本质上不会从任何地方调用任何资源,我们讨论的是PHP的DOMDocument类和XML starndards。

$schemaPath始终是相同的,它指向服务器本地XSD文件,它始终存在,在验证尝试之前和之后,它是否成功。架构仅指向位于同一文件夹中的其他本地xsd文件,即<xs:include schemaLocation="schema2.xsd"/>

我能想到的唯一可能的答案是XSD文件是由方法定位的,但由于某种原因无法读取,因为光盘正忙。

导致执行该方法的原因需要这么长时间?

除了增加PHP的最大执行时间限制外,应采取哪些措施来防止错误发生?

XML和XSD文件非常小,实际上完全相同的XML和XSD通常需要不到~0.1秒的时间来验证,但是很少次(1000次中的~1次)执行时间超过30秒。

修改

我隔离了问题所以我发布了一个样本。

Schema.xsd:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema targetNamespace="http://www.foo.bar/Car" xmlns:SiiDte="http://www.foo.bar/Car" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:include schemaLocation="schema2.xsd"/>
    <xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsignature_v10.xsd"/><!-- just the standar signature schema -->
    <xs:element name="ROOT" type="SiiDte:ROOTDefType"/>
    <xs:complexType name="ROOTDefType">
        <xs:sequence>
            <xs:element name="Element"></xs:element>
            <xs:element ref="ds:Signature">
                <xs:annotation>
                    <xs:documentation>Firma Digital sobre Documento</xs:documentation>
                </xs:annotation>
            </xs:element>
        </xs:sequence>
        <xs:attribute name="version" type="xs:decimal" use="required" fixed="1.0"/>
    </xs:complexType>
</xs:schema>

Schema2.xsd:

<xs:schema targetNamespace="http://www.foo.bar/Car" xmlns:ns1="http://www.foo.bar/Car" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:simpleType name="MOOType">
        <xs:restriction base="xs:positiveInteger">
            <xs:enumeration value="1"/>
            <xs:enumeration value="2"/>
            <xs:enumeration value="3"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

代码:

// ... a bunch of ther code...

$XML =
    '<?xml version="1.0"?>
    <ROOT xmlns="http://www.foo.bar/Car" version="1.0">
        <Element ID="A1">hello</Element>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <Reference URI="#A1">
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>base64string</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>base64string</SignatureValue>
            <KeyInfo>
                <KeyValue>
                    <RSAKeyValue>
                        <Modulus>base64string</Modulus>
                        <Exponent>AQAB</Exponent>
                    </RSAKeyValue>
                </KeyValue>
                <X509Data>
                    <X509Certificate>base64string</X509Certificate>
                </X509Data>
            </KeyInfo>
        </Signature>
    </ROOT>'
;

$DD = new DOMDocument();
$DD -> loadXML($XML);
$i = 0;

while ($i < 100) {
    // ... a bunch of other code...

    libxml_use_internal_errors(true);
    $old_libxml_disable_entity_loader = libxml_disable_entity_loader(false);        $result = $DD -> schemaValidate(__DIR__ . '/schema.xsd');
    libxml_disable_entity_loader($old_libxml_disable_entity_loader); // Se desactiva nuevamente carga de entidades para descartar entidades maliciosas
    $i++;
    echo str_pad($i, 5) . ($result ? 'true' : 'false') . '<br>';

    // ... a bunch of other code...
}

1 个答案:

答案 0 :(得分:-1)

问题是整个脚本达到30秒标记,而不是单独执行DOMDocument :: schemaValidate()。

执行时间对应于完整的脚本执行,包括所有包含和迭代,以防万一。

考虑执行时间不计算在脚本之外花费的任何时间,例如流操作,数据库查询等。因此,例如,脚本可能看起来需要1分钟,而实际上它只需要15或30。请参阅http://php.net/manual/en/function.set-time-limit.php说明:

  

注意:set_time_limit()函数和配置指令   max_execution_time仅影响脚本的执行时间   本身。花在执行之外的活动上的任何时间   使用system(),流操作等系统调用的脚本   确定最大值时不包括数据库查询等   脚本运行的时间。在Windows上不是这样   测量时间是真实的。

这不是:: schemaValidate(),它需要30秒才能执行,它是完整的脚本。那么为什么一旦脚本达到30秒,错误就会落在schemaValidate()里面?因为altought :: schemaValidate()它是一个相对快速的执行方法,它必须是迭代中最复杂的代码,因此最大的机会是当执行schemaValidate时,错误在N次重复之后下降(在实际情况下N必须很多)。

所以答案是:: schemaValidate()消耗了大部分执行时间,因此错误总是在:: schemaValidate()执行时发生。