Breaking Changes in v1.10.00
Customizing and migrating to v1.10.00 will require some new changes.
Configuration
There are a few changes to the format of config.php in this version.
If you see a front page message, "Not allowed to run this file directly," then you are likely using an old version of config.php. The best practice is to make a copy of the new config-dist.php example file and then compare or copy the settings from your old file into the new file. When that's finished, the new file should be named config.php.
E-Mail settings are no longer required in the file-based configuration. You now have the option to delete those settings and visit the new E-Mail section of the Administration Panel.
Functions
As this is a major new version of XMB, there will be too many changes to the function signatures to list them all here. The most significant function differences will be highlighted.
Namespace
When you include the new header.php script in one of your custom files, it will leave nothing in the global namespace.
All functions, classes, and constants now fall under the \XMB namespace.
For example, getInt() is now called \XMB\getInt() unless you import it.
Many XMB functions have been converted to class methods.
For example, nav() is now \XMB\Core::nav(). It is not a static function, so you will need to retrieve the shared instance of Core before you can use it.
To that end, XMB offers a list of service locators in the \XMB\Services namespace. The shared core service is returned by calling \XMB\Services\core(). Note the locator names are all lowercase unlike the class names. Here is the suggested style:
namespace XMB;
require './header.php';
$core = Services\core();
$core->nav('Add me to the navbar.');
When services are needed from outside the XMB namespace, it looks best to import the Services namespace to reduce the need for slashes. Otherwise, they would need to be referenced by their full name like \XMB\Services\core().
namespace MyProject;
use XMB\Services;
require './header.php';
$core = Services\core();
$core->nav('Add me to the navbar.');
Critical Functions
Here are some of the most widely used functions from v1.9.12 and their new locations.
censor()has moved toSmileAndCensor.createLangFileSelect()has moved toTranslation.getForum()has moved toForums.fontSize()has moved toTheme\Manager.loadPhrases()has moved toTranslation.postedArray()has moved toValidation. Signature changed after the 2nd param.postedVar()has moved toValidation.redirect()only has the first 2 params.request_secure()signature changed after the 2nd param.template_secure()was removed. Please use the new Template system.xmb_mail()is nowEmail::send().
To help reduce the number of breaking changes, these files still contain plain functions with no dependencies:
include/format.phpinclude/validate.inc.php
Queries
There are two main changes that affect all database queries in XMB.
Global $db Service Locator
Instead of providing a global variable named $db, XMB now offers two services named db and sql.
For a direct replacement of the global shared object reference, just add this near the top of your file:
$db = Services\db();
If you need to create a 2nd database connection (to a different account or server) within your script, then use the revised class name instead:
$db2 = new \XMB\MySQLiDatabase(debug: false, logErrors: true); $db2->connect(...);
Internally, XMB is starting to use methods of the shared sql service instead of direct or prepared statements. This results in cleaner and more secure code. For example, to get the shared service and check your inbox:
$sql = Services\sql(); $vars = Services\vars(); $msgCount = $sql->countU2UInbox($vars->self['username']);
If you wish to write similar query methods, the best practice is to create your own object class rather than try to modify the XMB service.
The X_PREFIX Constant
Instead of providing a global constant named X_PREFIX, XMB now stores the $tablepre variable from config.php as a property of the shared vars service. The direct replacement looks like this:
$vars = \XMB\Services\vars(); $statement = 'SELECT * FROM' . $vars->tablepre . 'ranks';
Example Query
Here is an actual query from the old cp2.php file:
require 'header.php';
$query = $db->query("SELECT * FROM ".X_PREFIX."restricted ORDER BY id");
Here is how it changed in the new restrictions.php file during development of v1.10.00:
require ROOT . 'header.php';
$db = \XMB\Services\db();
$vars = \XMB\Services\vars();
$result = $db->query("SELECT * FROM " . $vars->tablepre . "restricted ORDER BY id");
As mentioned above, many of the old queries have been migrated into SQL object methods. By the time v1.10 entered beta testing, the example query changed again:
require ROOT . 'header.php'; $sql = Services\sql(); $restrictions = $sql->getRestrictions();
Templates
The template system has moved to the templates subdirectory of the website and is no longer stored in the database.
Deleted Functions
The loadtemplates() and template() functions do not exist in v1.10.00. They have been replaced by the shared template service. To render a simple template, the code now looks like this:
$template = Services\template();
$output = $template->process('file_name.php');
Registered Global Variables
This will be the first version of XMB where it is impossible to pass a variable directly from user input to template output.
In older versions, it was possible and sometimes adequate to sanitize a global variable such as $fid = (int) $fid; and use it in the template without further consideration.
Starting with v1.10.00 it is required to manually register each variable with the shared template service or a separate instance (discussed later). Here is how we might handle the old $fid input:
$template = Services\template();
$template->fid = \XMB\getInt('fid');
You might notice there isn't any defined property named fid in the underlying service. This is called a dynamic property and it was chosen as one of the cleanest styles available for coding.
Of course, most pages need more than one variable, so you might want to import the XMB function names or the entire namespace for an even cleaner look.
namespace XMB;
const ROOT = './';
require ROOT . 'header.php';
$template = Services\template();
$template->fid = getInt('fid');
$template->pid = getInt('pid');
If you want to use some XMB code in your own project or utility, it might be better to import specific functions. Your file will start to look more like this:
namespace MyProject;
use XMB\Services;
use function XMB\getInt;
require './header.php';
$template = Services\template();
$template->fid = getInt('fid');
$template->pid = getInt('pid');
To provide backward compatibility with old templates, the shared template service automatically registers four variables for you:
$full_url$lang$SETTINGS$THEME
In addition to that, there are more services automatically registering some variables with the shared template service so that the entire header.php template is always ready to render.
There is one caveat: This works for old variables, not the obsolete ones. Due to the removal of all global variables, any array elements of the settings and theme systems are no longer registered individually. In other words, the obsolete $bbname must be expressed as $SETTINGS['bbname'] and the obsolete $bordercolor must be expressed as $THEME['bordercolor']. There are similar concerns with the $lang array elements if you are trying to migrate from an obsolete version less than v1.9.
Full PHP Syntax
This is the biggest change to the templates themselves. Don't worry, there is a conversion script available for anyone who needs to convert old custom templates.
Templates are now processed as full PHP. In older versions, templates were stored in the website itself and processed as string literals to prevent remote code execution.
The preferred style for variable replacement is short tags. So instead of $full_url you would write <?= $full url ?>.
Working With Multiple Templates
In most situations, it is okay to use the shared template service without worrying about performance or unexpected results.
The most obvious exception would be a template that is recursive in nature or that calls multiple other templates for processing. In this case, you do need to worry about variable name collisions in the shared service.
The next exception would be a reusable function that needs to process templates. In this case, there is no way to know if the caller already used similar variable names that would get overwritten by the custom function.
In any situation where it's easier to use a separate template processor, simply create one:
$template = Services\template();
$vars = Services\vars();
$other = new \XMB\Template($vars);
$other->addRefs(); // Add this method call when you need the theme array.
$template->fid = 10;
$other->fid = 20;
$forum10 = $template->process('forum.php');
$forum20 = $other->process('forum.php');
Beware the header.php template should always be processed by the shared service because that's where XMB populates those variables.
Example Script
Here is an excerpt of the old faq.php script:
require 'header.php';
if ($SETTINGS['faqstatus'] == 'off' && $page != 'forumrules') {
header('HTTP/1.0 403 Forbidden');
loadtemplates('misc_feature_notavailable');
eval('$header = "'.template('header').'";');
eval('$featureoff = "'.template('misc_feature_notavailable').'";');
end_time();
eval('$footer = "'.template('footer').'";');
echo $header, $featureoff, $footer;
exit();
}
Here is the same code used in the development of v1.10.00. Notice the $footerstuff array is no longer set globally by the new version of the end_time() method. It must be passed to the desired template processor by the caller instead.
namespace XMB;
require './header.php';
$core = Services\core();
$template = Services\template();
$vars = Services\vars();
if ($vars->settings['faqstatus'] == 'off' && $page != 'forumrules') {
header('HTTP/1.0 403 Forbidden');
$header = $template->process('header.php');
$featureoff = $template->process('misc_feature_notavailable.php');
$template->footerstuff = $core->end_time();
$footer = $template->process('footer.php');
echo $header, $featureoff, $footer;
exit();
}
Example Template
Here is an excerpt of the old footer template.
<br /> $footerstuff[totaltime] $footerstuff[querynum] $footerstuff[phpsql] $footerstuff[load] $footerstuff[querydump] </td> </tr> </table>
Here is the same part of the new footer.php template in development of v1.10.00:
<br /> <?= $footerstuff['totaltime'] ?> <?= $footerstuff['querynum'] ?> <?= $footerstuff['phpsql'] ?> <?= $footerstuff['load'] ?> <?= $footerstuff['querydump'] ?> </td> </tr> </table>