XF 2.2 Error Help

Ozzy47

Well-known member
I have a customer that is getting this error: XF 2.2.2 and PHP 7.4.12
Code:
ParseError: syntax error, unexpected 'return' (T_RETURN), expecting function (T_FUNCTION) or const (T_CONST) in src/addons/Snog/TV/XF/Pub/Controller/Forum.php at line 402

    Composer\Autoload\includeFile() in src/vendor/composer/ClassLoader.php at line 322
    Composer\Autoload\ClassLoader->loadClass()
    spl_autoload_call()
    class_exists() in src/XF/Extension.php at line 172
    XF\Extension->extendClass() in src/XF/App.php at line 2811
    XF\App->extendClass() in src/XF/App.php at line 1567
    XF\App->XF\{closure}() in src/XF/Container.php at line 228
    XF\Container->create() in src/XF/App.php at line 2766
    XF\App->controller() in src/XF/Mvc/Dispatcher.php at line 289
    XF\Mvc\Dispatcher->dispatchClass() in src/XF/Mvc/Dispatcher.php at line 257
    XF\Mvc\Dispatcher->dispatchFromMatch() in src/XF/Mvc/Dispatcher.php at line 113
    XF\Mvc\Dispatcher->dispatchLoop() in src/XF/Mvc/Dispatcher.php at line 55
    XF\Mvc\Dispatcher->run() in src/XF/App.php at line 2300
    XF\App->run() in src/XF.php at line 488
    XF::runApp() in index.php at line 20

Code in question is:
PHP:
<?php

namespace Snog\TV\XF\Pub\Controller;

use XF\InputFilterer;
use XF\Mvc\ParameterBag;
use XF\Util\File;

class Forum extends XFCP_Forum
{
    /**
     * @param ParameterBag $params
     * @return \XF\Mvc\Reply\Error|\XF\Mvc\Reply\Redirect|\XF\Mvc\Reply\View
     * @throws \XF\Mvc\Reply\Exception
     * @throws \XF\PrintableException
     */
    public function actionPostThread(ParameterBag $params)
    {
        if ($this->isPost())
        {
            if (!$params->node_id && !$params->node_name) return parent::actionPostThread($params);
            $forum = $this->assertViewableForum($params->node_id ?: $params->node_name, ['DraftThreads|' . \XF::visitor()->user_id]);
            if (!in_array($forum->node_id, $this->options()->TvThreads_forum)) return parent::actionPostThread($params);

            $originalNode = $forum->node_id;
            $title = $this->filter('title', 'str');

            if ($this->options()->TvThreads_mix && !stristr($title, "themoviedb") && !is_numeric($title)) return parent::actionPostThread($params);
            if (!$forum->canCreateThread($error)) return $this->noPermission($error);
            $switches = $this->filter(['inline-mode' => 'bool', 'more-options' => 'bool']);
            if ($switches['more-options']) return parent::actionPostThread($params);
            if ($switches['more-options']) $switches['inline-mode'] = false;
            $thread = null;
            $post = null;
            $allowed = ($this->options()->TvThreads_use_genres ? false : true);

            if (!$allowed && empty($forum->TVnode->tv_genre)) return $this->error(\XF::phrase('snog_tv_error_no_genre'));

            $crosslink = ($this->options()->TvThreads_use_genres && $this->options()->TvThreads_crosslink ? true : false);
            if (\XF::visitor()->isShownCaptcha() && !$this->app->captcha()->isValid()) return $this->error(\XF::phrase('did_not_complete_the_captcha_verification_properly'));

            $comment = $this->plugin('XF:Editor')->fromInput('message');

            if (stristr($title, "themoviedb.org/movie/")) return $this->error(\XF::phrase('snog_tv_error_movie_id'));

            if (stristr($title, "themoviedb"))
            {
                if(stristr($title,'themoviedb.org/search')) return $this->error(\XF::phrase('snog_tv_error_id_not_valid'));

                // preg_match_all USED FOR FUTURE API PARAMETER CAPTURING
                preg_match_all('/\d+/', $title, $matches);

                if (!empty($matches))
                {
                    $tmdbid = $matches[0][0];
                }
                else
                {
                    $tmdbid = '';
                }
            }
            else if (is_numeric($title))
            {
                if (intval($title) == 0)
                {
                    $tmdbid = '';
                }
                else
                {
                    $tmdbid = $title;
                }
            }
            else
            {
                $tmdbid = '';
            }

            if (!$tmdbid) return $this->error(\XF::phrase('snog_tv_error_id_not_valid'));

            if (!$this->options()->TvThreads_multiple)
            {
                $exists = $this->finder('Snog\TV:TV')->where('tv_id', $tmdbid)->fetchOne();

                // SHOW ALREADY EXISTS - IF COMMENTS MADE POST TO EXISTING THREAD
                if (isset($exists->tv_id) && $comment)
                {
                    $thread = $this->finder('XF:Thread')->where('thread_id', $exists->thread_id)->fetchOne();
                    $replier = $this->service('XF:Thread\Replier', $thread);
                    $replier->setMessage($comment);
                    if ($forum->canUploadAndManageAttachments()) $replier->setAttachmentHash($this->filter('attachment_hash', 'str'));
                    $post = $replier->save();
                    return $this->redirect($this->plugin('XF:Thread')->getPostLink($post), 'Your comments have been posted in the existing thread for the TV show');
                }

                // SHOW ALREADY EXISTS - NO COMMENTS - SEND TO EXISTING THREAD
                if (isset($exists->tv_id))
                {
                    $thread = $this->finder('XF:Thread')->where('thread_id', $exists->thread_id)->fetchOne();
                    return $this->redirect($this->buildLink('threads', $thread));
                }
            }

            try
            {
                $response = \XF::app()->http()->client()->get("http://api.themoviedb.org/3/tv/" . $tmdbid . "?api_key=" . trim($this->options()->TvThreads_apikey) . "&language=" .
                    $this->options()->TvThreads_language . "&append_to_response=credits,videos");
            }
            catch (\GuzzleHttp\Exception\RequestException $e)
            {
                if (null !== $e->getResponse())
                {
                    $error = 'TMDb Error ' . $e->getResponse()->getStatusCode();
                    $error .= ': ' . $e->getResponse()->getReasonPhrase();
                }
                else
                {
                    $error = $e->getMessage();
                }

                return $this->error($error);
            }

            $tvData = \GuzzleHttp\json_decode($response->getBody(), true);
            $dataFilter = new InputFilterer();
            $tv = $dataFilter->filter($tvData, 'ARRAY');

            $genres = '';
            foreach ($tv['genres'] as $genre)
            {
                if ($genres) $genres .= ', ';
                $genres .= $genre['name'];

                // CHECK IF GENRE IS ALLOWED IN THIS FORUM
                if (!$allowed)
                {
                    if (in_array($genre['name'], $forum->TVnode->tv_genre)) $allowed = true;
                }
            }

            // GENRE NOT ALLOWED? CHECK ALL TV FORUMS
            if (!$allowed)
            {
                $tvForums = $this->finder('XF:Forum')->with('TVnode')->where('TVnode.node_id', '>', '')->fetch();
                $checkGenres = explode(',', $genres);

                foreach ($tvForums as $genreForum)
                {
                    foreach ($checkGenres as $genre)
                    {
                        if (in_array(trim($genre), $genreForum->TVnode->tv_genre))
                        {
                            $allowed = true;
                            $forum = $this->finder('XF:Forum')->where('node_id', $genreForum->node_id)->fetchOne();
                            break;
                        }
                    }
                }

                // LAST CHANCE CHECK FOR CATCHALL FORUM
                if (!$allowed)
                {
                    foreach ($tvForums as $genreForum)
                    {
                        if (in_array('All', $genreForum->TVnode->tv_genre))
                        {
                            $allowed = true;
                            $forum = $this->finder('XF:Forum')->where('node_id', $genreForum->node_id)->fetchOne();
                            break;
                        }
                    }
                }

                if (!$allowed) return $this->error(\XF::phrase('snog_tv_error_genre_not_allowed'));
            }

            $directors = '';
            if (isset($tv['created_by']))
            {
                foreach ($tv['created_by'] as $director)
                {
                    if ($directors) $directors .= ', ';
                    $directors .= $director['name'];
                }
            }

            $cast = '';
            if (isset($tv['credits']))
            {
                foreach ($tv['credits']['cast'] as $member)
                {
                    if ($cast) $cast .= ', ';
                    $cast .= $member['name'];
                }
            }

            $trailer = '';
            if (isset($tv['videos']['results']['0']))
            {
                foreach ($tv['videos']['results'] as $video)
                {
                    if ($video['site'] == 'YouTube')
                    {
                        $trailer = $video['key'];
                        break;
                    }
                }
            }

            $releasedate = '';
            if (!empty($tv['first_air_date'])) $releasedate = $tv['first_air_date'];
            $tvtitle = html_entity_decode($tv['name']);
            $plot = html_entity_decode($tv['overview']);

            if (isset($tv['poster_path']))
            {
                $tempDir = FILE::getTempDir();
                $tempPath = $tempDir . $tv['poster_path'];

                $src = "http://image.tmdb.org/t/p/w92" . $tv['poster_path'];
                $path = 'data://tv/SmallPosters' . $tv['poster_path'];
                $this->getTVimage($src, $path, $tempPath);

                $src = "http://image.tmdb.org/t/p/w185" . $tv['poster_path'];
                $path = 'data://tv/LargePosters' . $tv['poster_path'];
                $this->getTVimage($src, $path, $tempPath);
            }

            // CREATE DEFAULT THREAD/MESSAGE WITHOUT PRETTY FORMATTING
            $message = "[img]" . $this->getTVImageUrl(($tv['poster_path'] ? $tv['poster_path'] : '/no-poster.jpg')) . "[/img]" . "\r\n\r\n";
            $message .= "[B]" . \XF::phrase('title') . ":[/B] " . $tvtitle . "\r\n\r\n";
            if ($genres) $message .= "[B]" . \XF::phrase('snog_tv_genre') . ":[/B] " . $genres . "\r\n\r\n";
            if ($directors) $message .= "[B]" . \XF::phrase('snog_tv_creator') . ":[/B] " . $directors . "\r\n\r\n";
            if ($cast) $message .= "[B]" . \XF::phrase('snog_tv_cast') . ":[/B] " . $cast . "\r\n\r\n";
            if ($releasedate) $message .= "[B]" . \XF::phrase('snog_tv_first_aired') . ":[/B] " . $releasedate . "\r\n\r\n";
            if ($plot) $message .= "[B]" . \XF::phrase('snog_tv_overview') . ":[/B] " . $plot . "\r\n\r\n";
            if ($trailer) $message .= "[MEDIA=youtube]" . $trailer . "[/MEDIA]" . "\r\n\r\n";
            if (!$this->options()->TvThreads_force_comments) $message .= $comment;
            $title = $tvtitle;

            $creator = $this->service('XF:Thread\Creator', $forum);
            $creator->setContent($title, $message);

            $prefixId = $this->filter('prefix_id', 'uint');
            if ($prefixId && $forum->isPrefixUsable($prefixId)) $creator->setPrefix($prefixId);
            if ($forum->canEditTags()) $creator->setTags($this->filter('tags', 'str'));
            if (!$this->options()->TvThreads_force_comments && $forum->canUploadAndManageAttachments()) $creator->setAttachmentHash($this->filter('attachment_hash', 'str'));

            $setOptions = $this->filter('_xfSet', 'array-bool');
            if ($setOptions)
            {
                $thread = $creator->getThread();

                if (isset($setOptions['discussion_open']) && $thread->canLockUnlock())
                {
                    $creator->setDiscussionOpen($this->filter('discussion_open', 'bool'));
                }
                if (isset($setOptions['sticky']) && $thread->canStickUnstick())
                {
                    $creator->setSticky($this->filter('sticky', 'bool'));
                }
            }

            $customFields = $this->filter('custom_fields', 'array');
            $creator->setCustomFields($customFields);
            $creator->checkForSpam();

            /** @var \XF\Service\Thread\Creator $errors */
            if (!$creator->validate($errors)) return $this->error($errors);
            $this->assertNotFlooding('post');

            $thread = $creator->save();

            // SETUP POSTER WITH THREAD ID
            if ($tv['poster_path'] > '')
            {
                $posterName = '/' . $thread->thread_id . '-' . str_ireplace('/', '', $tv['poster_path']);

                // SMALL POSTER
                $oldpath = 'data://tv/SmallPosters' . $tv['poster_path'];
                $newpath = 'data://tv/SmallPosters' . $posterName;

                try
                {
                    \XF::app()->fs()->move($oldpath, $newpath);
                }
                catch (\League\Flysystem\FileNotFoundException $e) {}

                // LARGE POSTER
                $oldpath = 'data://tv/LargePosters' . $tv['poster_path'];
                $newpath = 'data://tv/LargePosters' . $posterName;

                try
                {
                    \XF::app()->fs()->move($oldpath, $newpath);
                }
                catch (\League\Flysystem\FileNotFoundException $e) {}
            }
            else
            {
                $posterName = '';
            }

            $replaceMessage = "[img]" . $this->getTVImageUrl(($tv['poster_path'] ? $tv['poster_path'] : '/no-poster.jpg')) . "[/img]" . "\r\n\r\n";
            $withReplacement = "[img]" . $this->getTVImageUrl(($posterName ? $posterName : '/no-poster.jpg')) . "[/img]" . "\r\n\r\n";

            if ($tv['poster_path'])
            {
                $post = $this->finder('XF:Post')->where('post_id', $thread->first_post_id)->fetchOne();
                $post->message = str_ireplace($replaceMessage, $withReplacement, $post->message);
                $post->save();
            }

            $tvem = $this->em()->create('Snog\TV:TV');
            $tvem->thread_id = $thread->thread_id;
            $tvem->tv_id = $tmdbid;
            $tvem->tv_title = $title;
            $tvem->tv_plot = $plot;
            $tvem->tv_image = (is_null($tv['poster_path']) ? '' : $tv['poster_path']);
            $tvem->tv_trailer = $trailer;
            $tvem->tv_genres = $genres;
            $tvem->tv_director = $directors;
            $tvem->tv_cast = $cast;
            $tvem->tv_release = $releasedate;
            if ($comment && !$this->options()->TvThreads_force_comments) $tvem->comment = $comment;
            $tvem->save(false, false);

            if ($comment && $this->options()->TvThreads_force_comments)
            {
                $replier = $this->service('XF:Thread\Replier', $thread);
                $replier->setMessage($comment);
                if ($forum->canUploadAndManageAttachments()) $replier->setAttachmentHash($this->filter('attachment_hash', 'str'));
                $replier->save();
            }

            if ($crosslink)
            {
                $tvForums = $this->finder('XF:Forum')->with('TVnode')->where('TVnode.node_id', '>', '')->fetch();
                $checkGenres = explode(',', $genres);
                $data = $thread->toArray(false);
                $noLink[] = $data['node_id'];
                unset($data['thread_id'], $data['node_id']);
                $data['first_post_id'] = 0;
                $data['discussion_type'] = 'redirect';

                foreach ($tvForums as $genreForum)
                {
                    foreach ($checkGenres as $genre)
                    {
                        if (in_array(trim($genre), $genreForum->TVnode->tv_genre) && !in_array($genreForum->TVnode->node_id, $noLink))
                        {
                            $noLink[] = $genreForum->node_id;
                            $data['node_id'] = $genreForum->node_id;

                            $crosslink = $this->em()->create('XF:Thread');
                            $crosslink->bulkSet($data);
                            $crosslink->save();
                            $crosslinkThreadId = $crosslink->getEntityId();

                            $redirect = $this->em()->create('XF:ThreadRedirect');
                            $redirect->thread_id = $crosslinkThreadId;
                            $redirect->target_url = $this->app()->router('public')->buildLink('nopath:threads', $thread);
                            $redirect->redirect_key = "thread-{$thread->thread_id}-{$thread->node_id}-";
                            $redirect->expiry_date = 0;
                            $redirect->save();

                            $tvem = $this->em()->create('Snog\TV:TV');
                            $tvem->thread_id = $crosslinkThreadId;
                            $tvem->tv_id = $tmdbid;
                            $tvem->tv_title = $title;
                            $tvem->tv_plot = $plot;
                            $tvem->tv_image = $tv['poster_path'];
                            $tvem->tv_genres = $genres;
                            $tvem->tv_director = $directors;
                            $tvem->tv_cast = $cast;
                            $tvem->tv_release = $releasedate;
                            $tvem->save(false, false);
                        }
                    }
                }
            }

            // MOVED HERE FOR COMPATIBLITY ISSUES WITH XenPorta REDIRECTING IN THE FUNCTION

            /** @var \XF\Service\Thread\Creator $creator */
            $this->finalizeThreadCreate($creator);

            if ($switches['inline-mode'] && $forum->node_id == $originalNode)
            {
                $viewParams = ['thread' => $thread, 'forum' => $forum];
                return $this->view('XF:Forum\ThreadItem', 'thread_list_item', $viewParams);
            }
            else if (!$thread->canView())
            {
                return $this->redirect($this->buildLink('forums', $forum, ['pending_approval' => 1]));
            }
            else
            {
                return $this->redirect($this->buildLink('threads', $thread));
            }
        }

        return parent::actionPostThread($params);
    }

Line 402 is return parent::actionPostThread($params);

I believe the code is correct, but I don't know why the error.
 
There's a missing closing curly brace right at the end. Is that just a copy/paste error?
 
I didn’t think there was anything wrong in the code. I just can’t figure out the cause of the error.

Customer rebuilt the master data, as well as disabled all other addons, but the error continues.
 
I think we have occasionally seen unusual and nonsensical errors as a result of a corrupted opcache before. It may be worth temporarily disabling PHP's opcache to see if that changes anything.

But also before that I'd also just verify that the file on the server is exactly what you think it is and hasn't been edited or corrupted on upload in any way.
 
Top Bottom