News:

Bored?  Looking to kill some time?  Want to chat with other SMF users?  Join us in IRC chat or Discord

Main Menu

Variable set in loadBoard() in Load.php, but Undefined when creating topic?

Started by MiY4Gi, July 27, 2012, 06:43:55 PM

Previous topic - Next topic

MiY4Gi

I've got very little php knowledge, but luckily browsing the various php files in SMF teaches you quite a bit about php syntax and usage, and interpreting php functions seems to be fairly straight forward. This is just so that you know I'm still a newbie.

Anyway, I'm busy troubleshooting a bug with the Anonymous Board mod and I've narrowed down the problem to the variable $context['anonymous_board'].

The variable is set inside the loadBoard() function in the Load.php file. The function Post2() in Post.php tries to call this variable, however the problem is that whenever a user creates a new topic then the variable isn't defined, although when a user replies to the topic then the variable is defined. If I define the variable directly in the Post2() function (e.g. $variable = 0;) then there's no problem. However the variable is stored in the database so it's Load.php's job to pull the variable's value and make it available for other functions, or so I believe.

I just don't get it. At first I thought that the problem might be the location of where in the Load.php file the variable is defined, however, if the variable is inside the loadBoard() function, doesn't it get defined before or when a user creates a topic inside a board?

My last resort I think would be to force the Post2() function to directly pull the $context['anonymous_board'] variable's value from the database instead of having Load.php do it. Do you guys have any idea what might be wrong?

Here's the mod if it helps: http://custom.simplemachines.org/mods/index.php?mod=993

Below is the relevant code inside the loadBoard() function.


{
$request = $smcFunc['db_query']('', '
SELECT
c.id_cat, b.name AS bname, b.description, b.num_topics, b.member_groups, b.anonymous_board,
b.id_parent, c.name AS cname, IFNULL(mem.id_member, 0) AS id_moderator,
mem.real_name' . (!empty($topic) ? ', b.id_board' : '') . ', b.child_level,
b.id_theme, b.override_theme, b.count_posts, b.id_profile, b.redirect,
b.unapproved_topics, b.unapproved_posts' . (!empty($topic) ? ', t.approved, t.id_member_started' : '') . '
FROM {db_prefix}boards AS b' . (!empty($topic) ? '
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})' : '') . '
LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = {raw:board_link})
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
WHERE b.id_board = {raw:board_link}',
array(
'current_topic' => $topic,
'board_link' => empty($topic) ? $smcFunc['db_quote']('{int:current_board}', array('current_board' => $board)) : 't.id_board',
)
);
// If there aren't any, skip.
if ($smcFunc['db_num_rows']($request) > 0)
{
$row = $smcFunc['db_fetch_assoc']($request);

// Set the current board.
if (!empty($row['id_board']))
$board = $row['id_board'];

                        // Is the board anonymous?
$context['anonymous_board'] = $row['anonymous_board'];

// Basic operating information. (globals... :/)
$board_info = array(
'id' => $board,
'moderators' => array(),
'cat' => array(
'id' => $row['id_cat'],
'name' => $row['cname']
),
'name' => $row['bname'],
'description' => $row['description'],
'num_topics' => $row['num_topics'],
'unapproved_topics' => $row['unapproved_topics'],
'unapproved_posts' => $row['unapproved_posts'],
'unapproved_user_topics' => 0,
'parent_boards' => getBoardParents($row['id_parent']),
'parent' => $row['id_parent'],
'child_level' => $row['child_level'],
'theme' => $row['id_theme'],
'override_theme' => !empty($row['override_theme']),
'profile' => $row['id_profile'],
'redirect' => $row['redirect'],
'posts_count' => empty($row['count_posts']),
'cur_topic_approved' => empty($topic) || $row['approved'],
'cur_topic_starter' => empty($topic) ? 0 : $row['id_member_started'],
);

// Load the membergroups allowed, and check permissions.
$board_info['groups'] = $row['member_groups'] == '' ? array() : explode(',', $row['member_groups']);

do
{
if (!empty($row['id_moderator']))
$board_info['moderators'][$row['id_moderator']] = array(
'id' => $row['id_moderator'],
'name' => $row['real_name'],
'href' => $scripturl . '?action=profile;u=' . $row['id_moderator'],
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_moderator'] . '">' . $row['real_name'] . '</a>'
);
}
while ($row = $smcFunc['db_fetch_assoc']($request));

// If the board only contains unapproved posts and the user isn't an approver then they can't see any topics.
// If that is the case do an additional check to see if they have any topics waiting to be approved.
if ($board_info['num_topics'] == 0 && $modSettings['postmod_active'] && !allowedTo('approve_posts'))
{
$smcFunc['db_free_result']($request); // Free the previous result

$request = $smcFunc['db_query']('', '
SELECT COUNT(id_topic)
FROM {db_prefix}topics
WHERE id_member_started={int:id_member}
AND approved = {int:unapproved}
AND id_board = {int:board}',
array(
'id_member' => $user_info['id'],
'unapproved' => 0,
'board' => $board,
)
);

list ($board_info['unapproved_user_topics']) = $smcFunc['db_fetch_row']($request);
}

if (!empty($modSettings['cache_enable']) && (empty($topic) || $modSettings['cache_enable'] >= 3))
{
// !!! SLOW?
if (!empty($topic))
cache_put_data('topic_board-' . $topic, $board_info, 120);
cache_put_data('board-' . $board, $board_info, 120);
}
}
else
{
// Otherwise the topic is invalid, there are no moderators, etc.
$board_info = array(
'moderators' => array(),
'error' => 'exist'
);
$topic = null;
$board = 0;
}
$smcFunc['db_free_result']($request);
}


Below is the relevant code in the Post.php file. You may notice that I even tried to require_once the Load.php, but the variable still stayed undefined. It's almost as if some code in the Load.php file is preventing the variable from being defined before topic is created, but defines it after the topic is created.


function Post2()
{

global $board, $topic, $txt, $modSettings, $sourcedir, $context;
global $user_info, $board_info, $options, $smcFunc, $row;

        if( !isset($context['anonymous_board']) )
        {
                require_once($sourcedir . '/Load.php');
        }   

        //$context['anonymous_board'] = 0;

// Anonymous board mod
if ( $context['anonymous_board'] && !isset($_POST['post_unanon']) )
{
// Destroy the identifing user data
$user_info['username'] = 'Anonymous';
$user_info['name'] = 'Anonymous';
$user_info['email'] = '';
$user_info['id'] = 0;
}

// Sneaking off, are we?
if (empty($_POST) && empty($topic))
redirectexit('action=post;board=' . $board . '.0');
elseif (empty($_POST) && !empty($topic))
redirectexit('action=post;topic=' . $topic . '.0');

// No need!
$context['robot_no_index'] = true;

// If we came from WYSIWYG then turn it back into BBC regardless.
if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message']))
{
require_once($sourcedir . '/Subs-Editor.php');

$_REQUEST['message'] = html_to_bbc($_REQUEST['message']);

// We need to unhtml it now as it gets done shortly.
$_REQUEST['message'] = un_htmlspecialchars($_REQUEST['message']);

// We need this for everything else.
$_POST['message'] = $_REQUEST['message'];
}

// Previewing? Go back to start.
if (isset($_REQUEST['preview']))
return Post();

Check out my new website, MyAnimeClub.net. I plan to create the largest anime community, and most fun and user-friendly anime forum in the world. It's still in the development stage though.

Arantor

You're making it a lot more complicated for yourself.

Just test for !empty($context['anonymous_board'])

If it is an anonymous board, it'll be 1 (which is not empty), if it isn't, it'll be undefined or 0 (either of which is empty)

loadBoard() is run every page load regardless of anything else, and that part of that code should always be run. Just reloading (or not, as it would actually be in this case) Load.php will do nothing.

MiY4Gi

Yes, but no matter what the value of the variable, it should not give an undefined error if the variable has been declared in loadBoard() in Load.php, right? The issue is that when Post2() in Post.php tries calling the variable, then it sees it as undefined, even though the variable IS defined in loadBoard() in Load.php.

I tried the change you suggested, but it didn't work. And it also "hid" the error from the Error Log since !empty($variable) doesn't report a warning if the variable doesn't exist/ is undefined.
Check out my new website, MyAnimeClub.net. I plan to create the largest anime community, and most fun and user-friendly anime forum in the world. It's still in the development stage though.

Arantor

QuoteI tried the change you suggested, but it didn't work. And it also "hid" the error from the Error Log since !empty($variable) doesn't report a warning if the variable doesn't exist/ is undefined.

Um, it's supposed to do that, that's the point of the test.

Anyway, I know the reason this is failing at this point. You're trying to port this mod from 1.1.x to 2.0 and there's one huge thing that hasn't been taken into account: things are cached in 2.0, like the board data. (But they're not cached as much when a topic is declared in the URL, such as it will be in replies)

Instead of pushing it into $context where it is, push it into $board_info. This will ensure it is saved in the cache and also loaded in the cache. Then after the piece of code you quoted (entirely AFTER it), then pull it from $board_info to $context.

MiY4Gi

Great stuff. It's working now. Thanks. I believe this fix will make a lot of users very happy.

I wasn't sure what you meant by "push it into $board_info", so I improvised, but I guess I interpreted it correctly.

Here's the current, relevant loadBoard() code:


if (empty($temp))
{
$request = $smcFunc['db_query']('', '
SELECT
c.id_cat, b.name AS bname, b.description, b.num_topics, b.member_groups, b.anonymous_board,
b.id_parent, c.name AS cname, IFNULL(mem.id_member, 0) AS id_moderator,
mem.real_name' . (!empty($topic) ? ', b.id_board' : '') . ', b.child_level,
b.id_theme, b.override_theme, b.count_posts, b.id_profile, b.redirect,
b.unapproved_topics, b.unapproved_posts' . (!empty($topic) ? ', t.approved, t.id_member_started' : '') . '
FROM {db_prefix}boards AS b' . (!empty($topic) ? '
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})' : '') . '
LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = {raw:board_link})
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
WHERE b.id_board = {raw:board_link}',
array(
'current_topic' => $topic,
'board_link' => empty($topic) ? $smcFunc['db_quote']('{int:current_board}', array('current_board' => $board)) : 't.id_board',
)
);
// If there aren't any, skip.
if ($smcFunc['db_num_rows']($request) > 0)
{
$row = $smcFunc['db_fetch_assoc']($request);

// Set the current board.
if (!empty($row['id_board']))
$board = $row['id_board'];

// Basic operating information. (globals... :/)
$board_info = array(
'id' => $board,
'moderators' => array(),
'cat' => array(
'id' => $row['id_cat'],
'name' => $row['cname']
),
'name' => $row['bname'],
'description' => $row['description'],
'num_topics' => $row['num_topics'],
'unapproved_topics' => $row['unapproved_topics'],
'unapproved_posts' => $row['unapproved_posts'],
'unapproved_user_topics' => 0,
'parent_boards' => getBoardParents($row['id_parent']),
'parent' => $row['id_parent'],
'child_level' => $row['child_level'],
'theme' => $row['id_theme'],
'override_theme' => !empty($row['override_theme']),
'profile' => $row['id_profile'],
'redirect' => $row['redirect'],
'posts_count' => empty($row['count_posts']),
'cur_topic_approved' => empty($topic) || $row['approved'],
'cur_topic_starter' => empty($topic) ? 0 : $row['id_member_started'],
                                'anonymous_board' => $row['anonymous_board'],
);

// Load the membergroups allowed, and check permissions.
$board_info['groups'] = $row['member_groups'] == '' ? array() : explode(',', $row['member_groups']);

do
{
if (!empty($row['id_moderator']))
$board_info['moderators'][$row['id_moderator']] = array(
'id' => $row['id_moderator'],
'name' => $row['real_name'],
'href' => $scripturl . '?action=profile;u=' . $row['id_moderator'],
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_moderator'] . '">' . $row['real_name'] . '</a>'
);
}
while ($row = $smcFunc['db_fetch_assoc']($request));

// If the board only contains unapproved posts and the user isn't an approver then they can't see any topics.
// If that is the case do an additional check to see if they have any topics waiting to be approved.
if ($board_info['num_topics'] == 0 && $modSettings['postmod_active'] && !allowedTo('approve_posts'))
{
$smcFunc['db_free_result']($request); // Free the previous result

$request = $smcFunc['db_query']('', '
SELECT COUNT(id_topic)
FROM {db_prefix}topics
WHERE id_member_started={int:id_member}
AND approved = {int:unapproved}
AND id_board = {int:board}',
array(
'id_member' => $user_info['id'],
'unapproved' => 0,
'board' => $board,
)
);

list ($board_info['unapproved_user_topics']) = $smcFunc['db_fetch_row']($request);
}

if (!empty($modSettings['cache_enable']) && (empty($topic) || $modSettings['cache_enable'] >= 3))
{
// !!! SLOW?
if (!empty($topic))
cache_put_data('topic_board-' . $topic, $board_info, 120);
cache_put_data('board-' . $board, $board_info, 120);
}
}
else
{
// Otherwise the topic is invalid, there are no moderators, etc.
$board_info = array(
'moderators' => array(),
'error' => 'exist'
);
$topic = null;
$board = 0;
}
$smcFunc['db_free_result']($request);
}

        // Is the board anonymous?   
$context['anonymous_board'] = $board_info['anonymous_board'];


I don't fully understand what was wrong. Does cache take preference over other data, so that if data isn't loaded into cache it gets ignored? Does the 1st code line "if (empty($temp))" somehow relate to cache? Which data inside the loadBoard() function get cached? Everything including individual declared variables, or just the arrays like $board_info?

Check out my new website, MyAnimeClub.net. I plan to create the largest anime community, and most fun and user-friendly anime forum in the world. It's still in the development stage though.

Arantor

QuoteI wasn't sure what you meant by "push it into $board_info", so I improvised, but I guess I interpreted it correctly.

Yes, it simply means save it in $board_info somewhere.

QuoteDoes cache take preference over other data, so that if data isn't loaded into cache it gets ignored

Yes, that's sort of the point. Why go to the trouble of getting it from an expensive database query when you can get it cheaply from cache?

QuoteDoes the 1st code line "if (empty($temp))" somehow relate to cache?

Yes, if you look further up you'll see it attempt to fetch from cache and put it into $temp, and if $temp is empty, it wasn't available in the cache.

QuoteEverything including individual declared variables, or just the arrays like $board_info?

Um... the code you posted actually mentions it specifically. It saves the content of $board_info, if there's a topic it saves it slightly differently because of the difference in what was loaded. (That's what cache_put_data does...)

MiY4Gi

Thanks, I may never have figured out the problem without your help. I guess I'll mark this topic as solved.
Check out my new website, MyAnimeClub.net. I plan to create the largest anime community, and most fun and user-friendly anime forum in the world. It's still in the development stage though.

MiY4Gi

Just noticed now that SMF is still reporting an error in the Load.php file: Undefined index: anonymous_board. It only does this when a guest, or a spider, browses the forum.

As far as I can tell, it works fine for logged in users.

Any idea why this is happening?
Check out my new website, MyAnimeClub.net. I plan to create the largest anime community, and most fun and user-friendly anime forum in the world. It's still in the development stage though.

MiY4Gi

Bump.

Are there specific things in the Load.php files that don't get read/cached/whatever for guests, but do for logged-in users?
Check out my new website, MyAnimeClub.net. I plan to create the largest anime community, and most fun and user-friendly anime forum in the world. It's still in the development stage though.

Advertisement: