0

i have a problem cause probably design of site have been changed and my scrips doesn't work. The problem is

Fatal error: Uncaught Error: Call to a member function getElementsByTagName() on null in C:\xampik\htdocs\łamaki\open-triangle.php:177 Stack trace: #0 {main} thrown in C:\xampik\htdocs\łamaki\open-triangle.php on line 177

and in script this is: Line in script

    $tmp = explode('-', $current);
    $url = $siteURL.'/next/soccer/?year='.$tmp[0].'&month='.$tmp[1].'&day='.$tmp[2];

    $dom = new DOMDocument();
    $dom->loadHTML(execCURL($url));

    $table = $dom->getElementsByTagName('table')->item(0);
    foreach ($table->getElementsByTagName('tr') as $tr){
             ############################
        $isVisible = $tr->getAttribute('data-def');
        if($isVisible == 1){
            $meetingDate = trim($tr->getAttribute('data-dt'));
            $meetingDate = explode(',', $meetingDate);
            $meetingTime = $meetingDate[3].':'.$meetingDate[4];
            $meetingDate = $meetingDate[0].'.'.$meetingDate[1].'.'.$meetingDate[2];

what should i change? Any solve problem? I am completely green with this greetings

i tried to change path link

ADyson
  • 57,178
  • 14
  • 51
  • 63
Guzinek
  • 1
  • 1
  • 2
    [Please do not upload images of code/data/errors](//meta.stackoverflow.com/q/285551), images are hard to read and troubleshoot. Please [edit] your post and add the code here as text. Be sure to take the [tour] and read [ask]. - That said, `$table` is null, and you'll need to figure out why – aynber Aug 07 '23 at 13:50
  • 2
    `$dom->getElementsByTagName('table')->item(0)` is returning null. – GrumpyCrouton Aug 07 '23 at 13:50
  • 1
    you expect table to be present in curl response, which is no longer the case – Kazz Aug 07 '23 at 13:52
  • but previously it worked ( while code was >$table = $dom->getElementsByTagName('table')->item(0); ) , but design of site has been changed and i dont know how to fix it – Guzinek Aug 07 '23 at 13:54
  • Probably execCURL($url) is returning a null value. Please check it then process. – Sudipto Bhattacharya Aug 07 '23 at 14:11
  • Examine the new structure of the html and then adjust your code accordingly. – ADyson Aug 07 '23 at 14:29

1 Answers1

0

Your script is missing error handling and checking for data integrity in general.

Then when there is a slightest problem somewhere it might crash at a pretty unrelated different place (spooky action in the (nearer) distance, this at least looks like a straight forward script).

Some little tricks:

$tmp = explode('-', $current);

The beloved powerful explode(), it has a limit (third parameter) and you can provide defaults:

                                 #- three default values, we take null
                                 #
$tmp = explode('-', $current, 3) + [null, null, null];
                              #
                              #-- three array entries max

Now then those values are used, you should tell what they are, specifically when you put them into an URL (you don't want it to break at all cost), URLs need to be correct, always.

Better use sprintf(), here I assume you're using positive numbers:

$url = sprintf(
     '%s/next/soccer/?year=%d&month=%d&day=%d', 
     $siteURL, $tmp[0], $tmp[1], $tmp[2]
);

Better options there are with http_build_query() for building the query info part of an URI (I last used it in this answer), point in case is just that you need to encode it properly. Better productions likely then look like:

$date = array_combine(['year', 'month', 'day'], explode('-', $current));

This already shows the name + error handling (warning PHP < 8, ValueError since PHP 8). So more speaking and safe with current PHP, no need for the limit parameter of explode() here any longer!

$date = array_map(intval(...), $date);

Now every date item is integer. You may or may not need it when using

$date = array_combine(['year', 'month', 'day'], explode('-', $current));
$url = "{$siteUrl}/next/soccer/?" . http_build_query($date);

Sweet? But if you don't use http_build_query(), you need the intval() calls otherwise the URL risks to break.


Now so much for URL preparation. Let's check the place of use:

$dom = new DOMDocument();
$dom->loadHTML(execCURL($url))
    || throw new Error('HTML load error from: execCURL($url)');

Check function/mehtod returns, here loadHtml() returns false if there was an error. You want to handle it before proceeding. At least you want to know about it early, hence there (PHP 8.0+) directly throwing with the or "||" condition. This pattern you can use to integrate it quickly. Better throw an error then endless hours of debugging later errors.

Doing so will also show you that the error message then is not useful, which then will make you improve the code automatically at the right places.

Here it's that likely execCURL() does not return valid HTML (oh now hakre, that's clever!), perhaps not even a string(!). So we could have two classes of error, those curl already is able to detect, communicate (and perhaps even handle), and then the problem that the HTML Text (the document) itself is broken.

Not in your case. In your case the error is elsewhere, however you may want to be able to inspect the HTML at some point if later things run unexpected.


Now to the place you have the error with, at least we're getting closer:

$table = $dom->getElementsByTagName('table')->item(0);
foreach ($table->getElementsByTagName('tr') as $tr) {
   # ...

Here is another problem not properly understanding or better fully taking care of all the return types of $dom->getElementsByTagName('table')->item(0);.

And here's the news-flash: Two times:

  1. $dom->getElementsByTagName('table') may return null
  2. ->item(0) may return null

Both absolute correct return values by those methods. How to handle that in current PHP? Well, let the null pass through (null safe operator "?"):

$table = $dom->getElementsByTagName('table')?->item(0);
                                            #
                                            #- le magique question mark

And for the potential second null from item() return? Let's see:

foreach ($dom->getElementsByTagName('table')
            ?->item(0)
            ?->getElementsByTagName('tr') ?? [] as $tr) {
    # ...

Combined with the null-coalescing operator "??", foreach an empty array (do not foreach) if acessing tr elements in a null-safe manner resulted in null, otherwise the happy path of the tr elements.

Now three sections later and a couple of tricks and perhaps new things here, but all are centering around handling return and input values. Be respectful to them and treat them also respectful when you pass them along, e.g. in form of an URL to a different service. You never know where these little errors creep in either on your side nor at someones' else computer.

Write the code in a fail-safe way, error out early.


(code in this answer is untested so far and for example purposes only. PHP 8 .0+ language level.)

hakre
  • 193,403
  • 52
  • 435
  • 836