14

Apologies if this is real basic, but when PHP gets into functions I'm over my head.

I have a plug-in for a forum, which loads a flash cookie as a method to detect duplicate accounts.

The script is failing on about 0.1% of page views, causing a WSOD. The error points to this line:

return $this->registry->output->getTemplate( 'dml' )->duplicatesLoadMovie( $host, $path, $id, $md5 );

The error message is:

Fatal error: Call to a member function duplicatesLoadMovie() on null in /var/www/.../web/forums/hooks/duplicatesLoadMovie.php on line 75

To me, this reads as one of $host, $path, $id, or $md5 is returning null, but as this is not my script (and the coder is, of course, unresponsive), I would like to fix this in the simplest way possible (other than removing it, which is the fallback position).

Can I simply do something to the effect of $id = 0 if id.null? (sorry for the Rubyspeak) for each of the $variables?

Full source of the file:

class duplicatesLoadMovie
{ 
/**
 * Registry object shortcuts
 *
 * @var     $registry
 * @var     $settings
 * @var     $member
 * @var     $memberData
 **/
public $registry;
public $settings;
public $member;
public $memberData;

/**
 * Main function executed automatically by the controller
 *
 * @access  public
 * @return  @e void
 **/
public function __construct()
{
    $this->registry   = ipsRegistry::instance();
    $this->settings   =& $this->registry->fetchSettings();
    $this->member     = $this->registry->member();
    $this->memberData =& $this->registry->member()->fetchMemberData();
}

/**
 * Get the output
 *
 * @access  public
 * @return  @e string
 **/
public function getOutput()
{
    /* Grab host URL and installation path of the community */
    $host = $this->settings['board_url'];

    $parsed = parse_url( $host );
    $path = trim( $parsed['path'], '/' );
    if( $path == '' )
    {
        $path = '/';
    }

    $host = 'host=' . $host;
    $path = 'path=' . $path;

    /* Determine the appropriate identification method (member_id for members and session_id for guests) */
    if( $this->memberData['member_id'] )
    {
        $id = 'mid=' . $this->memberData['member_id'];
    }
    else
    {
        $id = 'sid=' . $this->member->session_id;
    }

    /* Grab the secure key for AJAX */
    $md5 = 'md5=' . $this->member->form_hash;

    /* Finally, call the template bit */
    return $this->registry->output->getTemplate( 'dml' )->duplicatesLoadMovie( $host, $path, $id, $md5 );
}
Dennis Kozevnikoff
  • 2,078
  • 3
  • 19
  • 29
Hoffa
  • 197
  • 1
  • 1
  • 12

2 Answers2

5

I'd suspect that this getTemplate( 'dml' ) is not returning a value. If you do a var_dump(getTemplate( 'dml' )), does it show anything?

You might check for "null" before doing that line of code, and in your "else" statement, output an error message, or some other action suitable for that error.

Source Matters
  • 1,110
  • 2
  • 15
  • 35
  • I'm sorry, I don't follow. This is called via a web page. Did you expect me to run this from the command line or php? – Hoffa Aug 04 '15 at 04:46
  • Huh? I know. For testing purposes, just before your "return" line, put this: var_dump(getTemplate( 'dml' )); exit(); That will output the value of that to your browser window so you can see if it's actually returning a value. I suspect that it is not, so because it's not returning a value (ie: null), you can't call the duplicatesLoadMovie method on it. – Source Matters Aug 04 '15 at 04:48
  • See, I told you PHP wasn't my thing :) I'll give that a try. – Hoffa Aug 04 '15 at 04:49
  • yep, that blew things up royally. All pages became WSOD with error: Call to undefined function getTemplate() – Hoffa Aug 04 '15 at 04:51
  • /* Finally, call the template bit */ // var_dump(getTemplate( 'dml' )); // exit(); return $this->registry->output->getTemplate( 'dml' )->duplicatesLoadMovie( $host, $path, $id, $md5 ); – Hoffa Aug 04 '15 at 04:52
  • try this instead: var_dump($this->registry->output->getTemplate( 'dml' )); exit(); – Source Matters Aug 04 '15 at 04:53
  • That sure got something :) Too much to paste in a comment... updating original – Hoffa Aug 04 '15 at 05:04
  • I've gone through it, and there's a ton of private information in there which shouldn't be posted. What sections should I be looking for? – Hoffa Aug 04 '15 at 05:07
  • No need to post any private info - you just want to confirm that it's actually outputting SOMETHING. What you can do is wrap your return statement in an if/else condition. If that "getTemplate" method is null, return some type of output message that you can use for debugging or alerting the user. It seems that in your 0.1% of occurrences, that it's returning blank for some reason. You don't do a lot of "integrity checks" in that code to test for blank values before using, so that might be something you consider adding. – Source Matters Aug 04 '15 at 05:10
  • if (is_null($this->registry->output->getTemplate( 'dml' ))) { var_dump($host, $path, $id, $md5 ); exit(); } --- does this sound about right? – Hoffa Aug 04 '15 at 05:18
  • some syntax errors in there, but that's the right idea. also note that "var_dump" is a debugging tactic. In production code, you'll want to output that to an error log, the console (maybe), or a usable message for the user. exit() will also end all output immediately. You'll remove that in live code. – Source Matters Aug 04 '15 at 05:24
2

Your problem is solved long time ago, but I suppose a lot of people looking for solution struggle with this error. PHP 8.0 introduces new operator nullsafe operator (?->). It's not for suppressing the error(!), but for cases when variable is allowed to be null and then we don't need to double check its value.

So in OP's question last row would look like:

return $this->registry->output->getTemplate( 'dml' )?->duplicatesLoadMovie( $host, $path, $id, $md5 );

It should be used very carefully, because it's not solution for every occurence of this kind of error!

Jsowa
  • 9,104
  • 5
  • 56
  • 60