Почему время выполнения DOMDocument::schemaValidate() для одних и тех же файлов XML и XSD иногда значительно превышает обычное?

Странно, что метод класса по умолчанию иногда дает сбой таким образом, даже если аргументы, переданные методу, совпадают, что обычно занимает доли секунды.

Превышено максимальное время выполнения 30 секунд в script_path в строке script_line_number

Именно в этой строке:

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

$DOMDocument всегда один и тот же. И он ссылается только на части одного и того же XML с атрибутами ID. У него нет атрибута типа URL, кроме атрибутов Algorith и xmlns, которые по своей природе не вызывают никаких ресурсов ниоткуда, и мы говорим о классе DOMDocument PHP и стандартах XML.

$schemaPath всегда один и тот же, и он указывает на локальный XSD-файл сервера, который всегда есть до и после попытки проверки, независимо от того, успешна она или нет. Схема указывает только на другие локальные файлы xsd, расположенные в той же папке, т.е. <xs:include schemaLocation="schema2.xsd"/>

Единственный возможный ответ, который я могу придумать, это то, что файл XSD находится по методу, но по какой-то причине он не может быть прочитан, потому что диск занят.

Что может быть причиной того, что выполнение метода занимает так много времени?

Какие меры следует предпринять, чтобы предотвратить возникновение ошибки, кроме увеличения максимального времени выполнения PHP?

Файлы XML и XSD довольно малы, на самом деле проверка одних и тех же файлов XML и XSD обычно занимает менее ~ 0,1 секунды, но очень редко (~ 1 из 1000) время выполнения превышает 30 секунд.


ИЗМЕНИТЬ

Я изолировал проблему, поэтому публикую образцы.

Схема.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>

Схема2.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...
}

person mikl    schedule 11.09.2015    source источник
comment
XSD file is located by the method but for some reason it cannot be read, because the disc is busy - или ему нужно что-то из сети, чего нет в данный момент?   -  person VolkerK    schedule 11.09.2015
comment
Скрипт не взаимодействует с клиентом, клиент его только выполняет, все данные хранятся на сервере. В любом случае то, что вы предлагаете, не имеет значения, потому что схема всегда находится по одному и тому же пути в файловой системе сервера, и если XML был искажен или не является DOMDocument, еще одна ошибка должна произойти один раз в строке schemaValidation (script_line_number), а не этот.   -  person mikl    schedule 11.09.2015
comment
а сама схема больше ничего не требует...из сети?   -  person VolkerK    schedule 11.09.2015
comment
нет, это просто текст, как и любой другой, хранящийся в файловой системе, они не ссылаются на какой-либо ресурс в сети. также у меня есть ini_set('allow_url_fopen', false); для безопасности. Схема ссылается только на локальные файлы, хранящиеся в той же папке (например: <xs:include schemaLocation="other_schema.xsd"/>).   -  person mikl    schedule 11.09.2015
comment
afaik, <xsd:include/import schemaLocation="http://..." не повлияет на allow_url_fopen=false. Но в любом случае, если вы говорите, что нет задействованного инет-ресурса, будем считать, что это исключено ;-)   -  person VolkerK    schedule 11.09.2015
comment
Вы также можете наблюдать такое поведение, если ваши документы XML, XSD или другие XML содержат DTD с общедоступным идентификатором, например XHTML DTD. Проверяющий XML-ридер попытается прочитать этот файл. Если это так, удалите проверку DTD, добавьте преобразователь URI, который разрешает URI локально (плюс храните DTD локально) или просто удалите объявление DTD, оно вам не понадобится, вы используете схему.   -  person Abel    schedule 11.09.2015
comment
Или, если у вас есть атрибут schemaLocation, который не использует парные токены (раздельные пробелы, в парах, URI и местоположение), возможно, позволяя синтаксическому анализатору думать, что он должен рассматривать его как местоположение. Известно, что некоторые парсеры XSD делают это, хотя технически такой атрибут неверен.   -  person Abel    schedule 11.09.2015
comment
Как и XML, у него нет атрибутов, ссылающихся на что-либо вне себя, у него есть только атрибуты xmlns, Algorithm с URL-адресами, похожими на строки, но эти атрибуты по своей природе ничего не вызывают.   -  person mikl    schedule 11.09.2015
comment
@Abel, расположение схемы — <xs:include schemaLocation="schema2.xsd"/>, т. е. ссылка на xsd, расположенный в той же папке. Он не разделен попарно, но проверка в 99% случаев выполняется успешно менее чем за 0,1 секунды с точно такими же XML и схемами.   -  person mikl    schedule 11.09.2015
comment
@mikl, я не это имел в виду. Я имел в виду ссылочную схему или проверяемый вами XML, который содержит атрибут schemaLocation в корне. Вы там проверяли?   -  person Abel    schedule 11.09.2015
comment
@Abel, всего три связанных схемы, ни одна из них не ссылается ни на что в сети, так же, как я описал с $DOMDocument, schema.xsd и schema2.xsd   -  person mikl    schedule 11.09.2015
comment
Если у вас нет внешних проанализированных сущностей, нигде нет объявления dtd, если вы проверяли сетевой трафик с помощью сниффера, то единственное, о чем я могу думать, это проблема с блокировкой потока, редкость этого случая предполагает это. Я не знаю, как это исправить, кроме как вне процесса, это может быть ошибка в PHP, библиотеках или другом.   -  person Abel    schedule 11.09.2015


Ответы (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()? Поскольку, несмотря на то, что ::schemaValidate() это относительно быстрый метод для выполнения, он должен быть самым сложным кодом внутри итерации, следовательно, самая большая вероятность того, что ошибка возникает при выполнении schemaValidate после N повторений (в реальном случае N должно быть много).

Таким образом, ответ: ::schemaValidate() потребляет большую часть времени выполнения, поэтому ошибка возникает практически всегда, когда выполняется ::schemaValidate().

person mikl    schedule 11.09.2015