Gotcha. I guess in that case the best thing to do is just pull the piece of extern.php you want as a regular function on your site and skip the include route. That's what I'll probably do at some point as well.

That's what I was wondering -- if someone could somehow take advantage of this set up. I couldn't figure out exactly how you would do it though, since to the outside world you wouldn't have any way (or would you?) of knowing that this was pulling from a PunBB include. On my particular setup I made a few mods to the extern file so that news on my front page jumps to dedicated pages for those topics, not back to the boards -- basically just using a staff only Forum in the boards as a quick and easy way to post to other sections of the site. So if we've got a particular event, we can post a notice on the front page that jumps to www.mysite.com/event_name, which displays that main page post plus any other posts from that Forum.

I've been battling the same problem all day. Finally came up with a workaround -- probably not the best or most efficient way to do this but it will solve the problem.

Like you, I found that if I try to include extern.php with a relative path (ie: include"/forums/extern.php?action=news") it always failed. If I took off the query part (everything after the ?) it would pull the file but obviously show no results. If I use the absolute path (include"http://www.mysite.com/boards/extern.php etc.") then all is good... except that the global $pun_user info. isn't available to extern.php and neither is the cookie info. I wanted to be able to use that info. to conditionally display info. via extern.php -- like only showing the number of times a certain post has been viewed to admins and staff, not all visitors.

So, here's what I ended up doing:

In the calling page, for example index.php, I added the following lines to turn the $pun_user array into two strings, one with the names of each variable (like username, group_id) and one with the associated values (like joeblow, 2):
$keys=array_keys($pun_user);
$keys=implode(",",$keys);
$pun_user = implode(",",$pun_user);
$append = "&keys=".$keys."&pun_user=".$pun_user;

Then I pass that info. to extern.php by tagging $append onto the include like so:
include "http://www.mysite.com/forums/extern.php … amp;fid=14".$append;

Then I added some lines in extern.php to convert that info. back into the $pun_user array so that I can access them just like anywhere else.

$a="";
$b="";
$values="";
if(isset($_GET['keys'])) $a = $_GET['keys'];
if(isset($_GET['pun_user'])) $b = $_GET['pun_user'];
$a = explode (",",$a);
$b = explode (",",$b);
$num_var=count($b);
$c=array_chunk($a, $num_var);
$a=$c['0'];
$keys=array_values($a);
$values=array_values($b);
$pun_user = array();
for ($i = 0; $i < $num_var; $i++) {
$pun_user[$keys[$i]] = $values[$i]; }

What I'm doing here is first setting the variables we're going to use and checking to see if we have passed the $append info. (you might have instances of extern.php where you don't need that info. and this will prevent you from getting errors because extern.php is expecting $append).
$a="";
$b="";
$values="";
if(isset($_GET['keys'])) $a = $_GET['keys'];
if(isset($_GET['pun_user'])) $b = $_GET['pun_user'];

If $keys and $pun_user are set, I then turn them back into arrays via the explode() function.
$a = explode (",",$a);
$b = explode (",",$b);

Unless all of your users have filled out every possible field of user info. you're always going to end up with more field keys than field info -- as in, I didn't put in any IM or ICQ info. so those field names will be in the $keys array but will have no corresponding value in the $pun_user array. So I count the array that has your user values ($b) and then use the array_chunk() function to cut the $keys array to the same size:
$num_var=count($b);
$c=array_chunk($a, $num_var);
$a=$c['0'];

Finally, I'm using PHP4 so I don't have the array_combine() function available so the next lines were my workaround. Basically I just do a loop to add values to the array $pun_user.
$keys=array_values($a);
$values=array_values($b);
$pun_user = array();
for ($i = 0; $i < $num_var; $i++) {
$pun_user[$keys[$i]] = $values[$i]; }

There you go. Probably not the most elegant way to handle this and I don't know if there are any security implications (you are passing all of this info. via a $_GET), but it's working for me. After that access any of the $pun_user variables within extern.php just like you use them elsewhere.

Here's the answer to the question about controlling the redirect when you log out and capturing the user names.

If you open the login.php file you'll see that on approx. line 85 (can't remember if I've made changes to the file that would make my line numbers different from yours) it reads "else if ($action == 'out')" -- that's the bit of code that handles logging out. The first part of it is a bit of a security feature -- looks to see if you are a guest user, if your user id isn't set, etc. Basically if you're someone who shouldn't even be seeing the log out option b/c you're not properly logged in in the first place. If any of those conditions are true it sends you back to the index page via the line "header(Location: index.php)".

Assuming you are logged in correctly, it goes about logging you out and updating the last visit info. On line 100 (again, I might have slightly different line numbers) it reads "pun_setcookie(1, random_pass(8), time() +31536000);". The next line (101 for me) is the one that tells it where to send a user after they've logged out. To stay on the same page, change it to the following:

redirect($_SERVER['HTTP_REFERER'], $lang_login['Logout redirect']);

If you want to redirect to a set page every time, just replace $_SERVER with the URL -- ie: redirect(http://www.yoursite.com/index.php);

As for the user names, you enter them into a database the same as you would any other info. -- I do this for events that people enter on my site. I use $pun_user['id'] rather than user name because it's smaller to store in the dbase and is guaranteed to be unique. My MySQL query for adding a new event to the dbase reads "INSERT INTO table_name (event_title, event_date, etc, user) VALUES ('".$_REQUEST['event_title']."', '".$_REQUEST['event_date']."',...,'$pun_user['id']')"

Then to display the user name along with their comment, simply pull it from the pun_user table. Here's the query I use to do that:
$detailquery = "SELECT c.*, b.username AS poster, b2.username AS editor FROM calendar_events AS c LEFT JOIN bb_users AS b on (c.poster_id = b.id) LEFT JOIN bb_users AS b2 on (c.edited_by=b2.id) WHERE c.EventId = $Id";

Basically I'm saying select all fields from a table whose name I'm abbreviating as "c" (SELECT c.*). Also select the field "username" from a second table that I'm abbreviating as "b" (b.username) and instead of calling the field "username", call it "poster" (b.username AS poster). In my set up I want to know both who originally posted an event ("poster") and if someone edited it, who that person was ("editor"). Since both editor and poster are identified in my event record by their punbb user id, I need to check against the pun_users table twice for the matching user names. So I select the bb_users table again, this time aliasing it as b2 (b2.username) and I call the second instance of username "editor" (b2.username AS editor). In my FROM clause I tell MySQL which abbreviation corresponds with which table, so "calendar_events AS c" tells it that "c.*" is the same as "calendar_events.*". The LEFT JOIN tells tells is to match the user_id stored as "poster" in calendar_events with the pun user id stored in bb_users, then do another match for "editor". The end result is that $row['poster'] returns the user name of the person who posted the event and $row['editor'] returns the name of the last person to edit the event (I only store the last person, if you wanted to track each person who edits it -- like for an editorial production flow -- you'd need to do it differently).

Feel free to contact me if any of the above doesn't make sense. If anyone is interested, I'm just finishing up adding a feature so that when events are posted it automatically emails certain admin users and based on the group the user belongs to the event can either be immediately posted (like when a staffer posts it) or held pending approval by someone on staff. It's all working at this point and in, just doing the tidying up work now.

This is fabulous, thanks!

Thnx, glad it's working for you. I'm using it on http://www.ontaponline.com (log in is on the top right of the screen).

Problem is the the first two lines:

define('PUN_ROOT', './forums');
include 'forums/include/common.php';

You've set up the right path in the second line b/c it is loading the common.php file. The first thing it looks at once it loads that file is the value of PUN_ROOT to make sure there is a valid config. file. It's not finding one, so it's assuming that it is a new installation of PunBB. Make sure the PUN_ROOT you have defined is correct *relative to where the file is getting called from. Meaning:

MYSITE --> is where all your pages and subfolders are
MYSITE --> FORUMS --> is where all of your PunBB files are
MYSITE --> TEST PAGES --> is where you have the test page you're working on

In that type of setup your PUN_ROOT would be ./FORUMS
If your test page was sitting right in the MYSITE folder then the PUN_ROOT would be /FORUMS

The exact path depends on your server setup, but that's what is going to fix the problem.

Thanks, missed that one. Noticed that I was missing the closing </a> tag on the log out link as well (it says </div>, not </a>). Also, made a couple of improvements to the code. As written above it doesn't account for the fact that your particular page may have additional variables in the URL you used to reach it initiall. EX: You're on a calendar page that used $month and $year to list the appropriate events. If you use the code above, when you log in you will be redirected back to that same calendar page but without the $month and $year values. Simply change the redirect line from:

<input type=\"hidden\" name=\"redirect_url\" value=\"".$_SERVER['SCRIPT_NAME']."\" />

to:

<input type=\"hidden\" name=\"redirect_url\" value=\"".$_SERVER['PHP_SELF']."?".$_SERVER['QUERY_STRING']."\" />


Also, same issue on log out. The method I have above doesn't handle the variables and is a bit of an awkward work around. Better solution is to change the log out link from:

<ahref=\"/forums/login.php?action=out&id=".$pun_user['id']."&location_out=".$_SERVER['SCRIPT_NAME']."\">here</a> to log out.</a>

to:

<a href=\"/boards/login.php?action=out&id=".$pun_user['id']."\">Log out</a>

Then eliminate all of the edits to PunBB's login.php file that I put above (the stuff about $location_out) and simply change the log out redirect to read:

redirect($_SERVER['HTTP_REFERER'], $lang_login['Logout redirect']);

I've seen a bunch of different posts on this topic and none of them was really doing the job for me -- probably b/c I'm fairly new to PHP and didn't quite get what other people were doing. If you're looking for simple steps to simply use PunBB's user login system across your site (ie: having a box on the homepage where people can sign in, or that conversely recognizes that they're already signed in and offers them the option to sign out) here's a pretty simple way to do it.

1. For practice purposes, create a new blank php file called "pun_test.php".

2. Put the following two lines at the top:
define('PUN_ROOT', './forums');
include 'forums/include/common.php';

In the first line, ./forums should be the relative path to your PunBB files from the pun_test.php file. In the second line, forums should be replaced with whatever you have called that folder.

3. I chose to put the login/logout stuff in a function. That way I can add it to any page on my site just by calling the function. For example purposes, make another php file and call it login_function.inc.php. The ".inc" isn't necessary, but as your site gets more complex it will help you keep different types of files organized.

4. Your pun_test.php file needs to know the location of your function file, so add the following line:
include './login_function.inc.php'
Again, that path is assuming it's in the same folder as pun_test.php. If not, you'll need to change your path accordingly.

5. Last thing you'll need in your pun_test.php file is the actual call to the function. I called the function login_menu, so all you need to add is:
login_menu();

Your finished pun_test.php file should look like this:

<?php
define('PUN_ROOT', './forums');
include 'forums/include/common.php';
include './login_function.inc.php'

login_menu();
?>

6. Now for the function. The first thing you need to do is name the function you're going to define.
<?php

function login_menu() {

7. Next you need to declare some global variables that are used by PunBB. What does this mean? Simply that PunBB assigns values to a bunch of variables -- like user name, password, etc. -- and makes them available for use throughout the site. But your function won't know they are available until you specifically tell it so. All you need for the login/logout box are the values stored in $pun_user:

global $pun_user;

8. First thing we're going to do in the function is see if the user is logged in. If they aren't, we want them to see the login box. This part I took directly from someone else's post (my apologies, I don't remember which one. Thanks whoever you are!)

if ($pun_user['is_guest']) {
  echo "<form id=\"login\" method=\"post\" action=\"/forums/login.php?action=in\" onsubmit=\"return process_form(this)\">
<input type=\"hidden\" name=\"form_sent\" value=\"1\" />
<input type=\"hidden\" name=\"redirect_url\" value=\"".$_SERVER['SCRIPT_NAME']."\" />
<input type=\"text\" name=\"req_username\" size=\"25\" maxlength=\"25\" />
<input type=\"password\" name=\"req_password\" size=\"16\" maxlength=\"16\" />
<input type=\"submit\" name=\"login\" value=\"Login\" />
</form>";
    }

Again, this is looking at the 'is_guest' value of $pun_user. If it is set, meaning they are a guest, then it shows the following lines of code which make the form. You can edit this to use your own styles, fonts, etc. This is just a super basic thing with two fields for user and password and a submit button. The person who originally posted made a nice addition to his code though with the line that reads "<input type=\"hidden\" name=\"redirect_url\" ... " etc. That line just says that when someone submits the form, come back to whatever page the form is on. So if you add the box to your homepage, when someone logs in they'll be taken back to your homepage, not to the PunBB index page.

9. The other option is that someone is already logged in. In that case you want to show them a nice little "Welcome [username]" type message and a link to log back out. Here's the code for that part:

else {
echo "Logged in as: ".pun_htmlspecialchars($pun_user['username'])."<br> Last visit: ". format_time($pun_user['last_visit'])."
<br>Click <a href=\"/forums/login.php?action=out&id=".$pun_user['id']."&location_out=".$_SERVER['SCRIPT_NAME']."\">here</a> to log out.</div>";
}

10. In my logout link I've passed a new variable, "$location_out". That's because I want someone logging out to return to the same page, not to the PunBB login screen. A couple of quick modifications to the login.php file in PunBB make this work.

11. Last thing you need is your final } to close out the function and the ?> to close out the page. Your complete login_function.inc.php file should look like this:

<?php

function login_menu() {
global $pun_user;

if ($pun_user['is_guest']) {
  echo "<form id=\"login\" method=\"post\" action=\"/forums/login.php?action=in\" onsubmit=\"return process_form(this)\">
<input type=\"hidden\" name=\"form_sent\" value=\"1\" />
<input type=\"hidden\" name=\"redirect_url\" value=\"".$_SERVER['SCRIPT_NAME']."\" />
<input type=\"text\" name=\"req_username\" size=\"25\" maxlength=\"25\" />
<input type=\"password\" name=\"req_password\" size=\"16\" maxlength=\"16\" />
<input type=\"submit\" name=\"login\" value=\"Login\" />
</form>";
    }
else {
echo "Logged in as: ".pun_htmlspecialchars($pun_user['username'])."<br> Last visit: ". format_time($pun_user['last_visit'])."
<br>Click <a href=\"/forums/login.php?action=out&id=".$pun_user['id']."&location_out=".$_SERVER['SCRIPT_NAME']."\">here</a> to log out.</a>";
}
}
?>

10. Okay, you're just about done here. Last step is to open up the login.php file in your PunBB folder. Go to line 85 which reads: else if ($action == 'out'). This is the piece of code that handles processing of a log out request for PunBB.

Right after line 86, (which is simply a curly bracket { ), I added the following lines:
if(isset($_GET['location_out'])){
$location_out=$_GET['location_out'];
}
else{
$location_out="index.php";
}

What those do is look to see if you're logging out from a non-PunBB page on your site. If you are, our logout function will be passing the location_out variable and PunBB will use this as the address to redirect you to after logging out. If the user was in your boards, however, there won't be a location_out variable b/c they'll be using PunBB's built in logout script. So in that case we simply set location_out to the same value PunBB was using originally.

11. Finally, go to what is now line 108. It should read: redirect('index.php', $lang_login['Logout redirect']);
Change that to: redirect($location_out, $lang_login['Logout redirect']);

That's it. If you open your pun_test.php file in a browser now you'll see your basic login form. Put in your user name and pass and submit and it will take you back to that same page, only now it will show you your user name, the last time you logged in, and a link to log out. If you manually go to your PunBB index page you'll see that it recognizes that you're logged in. Anywhere on your site you want to include your new login box just put the three lines at the start of the file (the include / define / include that are at the start of pun_test.php) and then wherever on your page you want the box to appear just call your new function: login_menu();

As you play around you'll see that it is easy to change what info. it shows once you are logged in, the look of the form, etc.

Scanned over for typos but let me know if you have any problems with this or need any help.