fb-instant-articles icon indicating copy to clipboard operation
fb-instant-articles copied to clipboard

cloneNone() doesn't check for null

Open paulschreiber opened this issue 7 years ago • 7 comments

Steps required to reproduce the problem

  1. Load http://fivethirtyeight.com/features/hot-takedown-wonders-do-stars-matter/

Expected Result

No error

Actual Result

Error: Uncaught exception 'Error' with message 'Call to a member function cloneNode()
on null' in /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-
instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php:105

Version Info

Please state exact versions, not latest or new.

  • Plugin version: 4.1.1
  • WordPress version: 4.9.8
  • PHP version: 7.2

Immediate cause: do a null check here:

    public static function cloneNode($node)
    {
        $clone = $node->cloneNode(true);
        if (Type::is($clone, 'DOMElement') && $clone->hasAttribute(self::INSTANT_ARTICLES_PARSED_FLAG)) {
            $clone->removeAttribute(self::INSTANT_ARTICLES_PARSED_FLAG);
        }
        return $clone;
    }

Full stack trace:

in Facebook\InstantArticles\Transformer\Transformer::cloneNode called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/MultipleElementsGetter.php (34)
in Facebook\InstantArticles\Transformer\Getters\MultipleElementsGetter::get called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/ConfigurationSelectorRule.php (160)
in Facebook\InstantArticles\Transformer\Rules\ConfigurationSelectorRule::getProperty called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/InteractiveRule.php (82)
in Facebook\InstantArticles\Transformer\Rules\InteractiveRule::apply called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php (338)
in Facebook\InstantArticles\Transformer\Transformer::transform called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/PassThroughRule.php (32)
in Facebook\InstantArticles\Transformer\Rules\PassThroughRule::apply called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php (338)
in Facebook\InstantArticles\Transformer\Transformer::transform called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/PassThroughRule.php (32)
in Facebook\InstantArticles\Transformer\Rules\PassThroughRule::apply called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php (338)
in Facebook\InstantArticles\Transformer\Transformer::transform called at /var/www/wp-content/plugins/vip/facebook-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php (265)
in Facebook\InstantArticles\Transformer\Transformer::transformString called at /var/www/wp-content/plugins/vip/facebook-instant-articles/class-instant-articles-post.php (699)
in Instant_Articles_Post::to_instant_article called at /var/www/wp-content/plugins/vip/facebook-instant-articles/class-instant-articles-post.php (886)
in Instant_Articles_Post::is_empty_after_transformation called at /var/www/wp-content/plugins/vip/facebook-instant-articles/class-instant-articles-post.php (963)
in Instant_Articles_Post::should_submit_post called at /var/www/wp-content/plugins/vip/facebook-instant-articles/facebook-instant-articles.php (385)
in inject_ia_markup_meta_tag called at /var/www/wp-includes/class-wp-hook.php (286)
in WP_Hook::apply_filters called at /var/www/wp-includes/class-wp-hook.php (310)
in WP_Hook::do_action called at /var/www/wp-includes/plugin.php (453)
in do_action called at /var/www/wp-includes/general-template.php (2614)
in wp_head called at /var/www/wp-content/themes/espn-fivethirtyeight/header.php (10)
in require_once called at /var/www/wp-includes/template.php (688)
in load_template called at /var/www/wp-includes/template.php (647)
in locate_template called at /var/www/wp-includes/general-template.php (41)
in get_header called at /var/www/wp-content/themes/espn-fivethirtyeight/single-fte_features.php (57)
in include called at /var/www/wp-includes/template-loader.php (74)
in require_once called at /var/www/wp-blog-header.php (19)
in require called at /var/www/index.php (17)

paulschreiber avatar Nov 06 '18 20:11 paulschreiber

Perhaps the check should be added to $child->get($node) before it is passed in.

public function get($node)
{
    $fragment = $node->ownerDocument->createDocumentFragment();
    foreach ($this->children as $child) {
        $cloned_node = Transformer::cloneNode($child->get($node));
        if (Type::is($cloned_node, 'DOMNode')) {
            $fragment->appendChild($cloned_node);
        }
    }
    if ($fragment->hasChildNodes()) {
        return $fragment;
    }
    return null;
}

paulschreiber avatar Nov 07 '18 02:11 paulschreiber

I'm seeing the same error as well after migrating a site to a PHP 7.2 box:

PHP message: PHP Fatal error:  Uncaught Error: Call to a member function cloneNode() on null in /var/www/[domain]/htdocs/wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php:105

WordPress version: 5.2.1 Pluign version: 4.2.0 PHP version: 7.2.19

georgetasioulis avatar Jun 18 '19 08:06 georgetasioulis

We are receiving the same error as well. Has anyone found a solution?

dsmikeyorke avatar Oct 22 '19 16:10 dsmikeyorke

@paulschreiber do you have this patch implemented on a website? If so, does everything seem to be working as expected?

dsmikeyorke avatar Oct 22 '19 16:10 dsmikeyorke

@dsmikeyorke It doesn't address the root cause, but does reduce the amount of noise from spurious errors.

paulschreiber avatar Oct 22 '19 17:10 paulschreiber

Not sure if the issue I faced is the same as the OP. We were getting this error because of an incomplete Twitter embed code. Re-copied the complete embed code and the problem went away.

imadsani avatar Feb 18 '20 11:02 imadsani

Getting this error specifically as part of #1030. Probably a deeper issue there, but this is how it's manifesting.

ethanclevenger91 avatar May 28 '20 16:05 ethanclevenger91

I'm unable to reproduce this. A source markup of:

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Ferger Place Historic District<a href="https://t.co/atGXcNFbxU">https://t.co/atGXcNFbxU</a> <a href="https://t.co/iATarwphXn">pic.twitter.com/iATarwphXn</a></p>&mdash; Wiki Titles Singable to TMNT Themesong (@wiki_tmnt) <a href="https://twitter.com/wiki_tmnt/status/1140665423291023360?ref_src=twsrc%5Etfw">June 17, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></blockquote>

(as per #1030), gives a transformed markup of:

<figure class="op-interactive">
        <iframe class="no-margin">
          <blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Ferger Place Historic District<a href="https://t.co/atGXcNFbxU">https://t.co/atGXcNFbxU</a> <a href="https://t.co/iATarwphXn">pic.twitter.com/iATarwphXn</a></p>— Wiki Titles Singable to TMNT Themesong (@wiki_tmnt) <a href="https://twitter.com/wiki_tmnt/status/1140665423291023360?ref_src=twsrc%5Etfw">June 17, 2019</a></blockquote>
          <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
        </iframe>
      </figure>

...though on viewing, the iframe is empty, but no PHP log is generated.

#1030 also mentioned about custom rules possibly being in play?

I'd rather not just hide the issue by checking for cloneNode() being applied to null, without knowing what the root cause is.

GaryJones avatar Oct 16 '22 02:10 GaryJones

Closing, but happy to re-open if there's some more info to work with.

GaryJones avatar Oct 16 '22 02:10 GaryJones

I did manage to replicate this today:

Stacktrace
Fatal error: Uncaught Error: Call to a member function cloneNode() on null in .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php:105
Stack trace:
#0 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/MultipleElementsGetter.php(34): Facebook\InstantArticles\Transformer\Transformer::cloneNode(NULL)
#1 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/ConfigurationSelectorRule.php(160): Facebook\InstantArticles\Transformer\Getters\MultipleElementsGetter->get(Object(DOMElement))
#2 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/InteractiveRule.php(82): Facebook\InstantArticles\Transformer\Rules\ConfigurationSelectorRule->getProperty('interactive.ifr...', Object(DOMElement))
#3 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php(336): Facebook\InstantArticles\Transformer\Rules\InteractiveRule->apply(Object(Facebook\InstantArticles\Transformer\Transformer), Object(Facebook\InstantArticles\Elements\InstantArticle), Object(DOMElement))
#4 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/PassThroughRule.php(32): Facebook\InstantArticles\Transformer\Transformer->transform(Object(Facebook\InstantArticles\Elements\InstantArticle), Object(DOMElement))
#5 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php(336): Facebook\InstantArticles\Transformer\Rules\PassThroughRule->apply(Object(Facebook\InstantArticles\Transformer\Transformer), Object(Facebook\InstantArticles\Elements\InstantArticle), Object(DOMElement))
#6 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/PassThroughRule.php(32): Facebook\InstantArticles\Transformer\Transformer->transform(Object(Facebook\InstantArticles\Elements\InstantArticle), Object(DOMElement))
#7 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php(336): Facebook\InstantArticles\Transformer\Rules\PassThroughRule->apply(Object(Facebook\InstantArticles\Transformer\Transformer), Object(Facebook\InstantArticles\Elements\InstantArticle), Object(DOMElement))
#8 .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php(265): Facebook\InstantArticles\Transformer\Transformer->transform(Object(Facebook\InstantArticles\Elements\InstantArticle), Object(DOMDocument))
#9 .../wp-content/plugins/fb-instant-articles/class-instant-articles-post.php(687): Facebook\InstantArticles\Transformer\Transformer->transformString(Object(Facebook\InstantArticles\Elements\InstantArticle), '\n<figure class=...', 'UTF-8')
#10 .../wp-content/plugins/fb-instant-articles/class-instant-articles-post.php(874): Instant_Articles_Post->to_instant_article()
#11 .../wp-content/plugins/fb-instant-articles/class-instant-articles-post.php(951): Instant_Articles_Post->is_empty_after_transformation()
#12 .../wp-content/plugins/fb-instant-articles/facebook-instant-articles.php(357): Instant_Articles_Post->should_submit_post()
#13 .../wp-includes/class-wp-hook.php(307): inject_ia_markup_meta_tag('')
#14 .../wp-includes/class-wp-hook.php(331): WP_Hook->apply_filters(NULL, Array)
#15 .../wp-includes/plugin.php(476): WP_Hook->do_action(Array)
#16 .../wp-includes/general-template.php(3042): do_action('wp_head')
#17 .../wp-includes/template-canvas.php(17): wp_head()
#18 .../wp-includes/template-loader.php(106): include('/Users/gary/Sit...')
#19 .../wp-blog-header.php(19): require_once('/Users/gary/Sit...')
#20 .../index.php(17): require('/Users/gary/Sit...')
#21 {main} thrown in .../wp-content/plugins/fb-instant-articles/vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php on line 105

Minimum trigger was a Custom HTML block with:

<blockquote class="twitter-tweet"></blockquote>

...as the only contents. Changing the class name, even by one letter stopped the issue. In the rules-configuration.json there's:

	{
        "class": "InteractiveRule",
        "selector" : "blockquote.twitter-tweet",
        "properties" : {
            "interactive.iframe" : {
                "type" : "multiple",
                "children": [
                    {
                        "type": "element",
                        "selector": "blockquote"
                    }, {
                        "type": "next-sibling-element-of",
                        "selector": "blockquote"
                    }
                ]
            }
        }
    }

...so the class name is important in determining behaviour.

If I'm reading that rule correctly (and this is somewhat of a guess as I've not looked inside the engine), then the transformation says to create an interactive.iframe thing, then add the current blockquote as a child, and then the next sibling element of the current blockquote. To test this, I updated my custom HTML block to:

<blockquote class="twitter-tweet"></blockquote><hr>

(i.e. gave a random next sibling element to the blockquote), and the fatal error disappeared. The NextSiblingElementGetter class does return null if a sibling element can't be determined, so that fits the error.

As such, I'd say that ensuring that the correct markup (blockquote + the expected script element to format the blockquote into a tweet) is the way to go here.

GaryJones avatar Oct 17 '22 23:10 GaryJones