SMF 2.0 with PHP 7

SMF does not officially support running version 2.0.x with PHP 7.0.  This is due to PHP removing the mysql library in favor of more secure MySQLi library.  To get around this if you have root access to your server, you could manually build in the old mysql library functions.  Or you know, build compatibility functions.  I’m releasing this as a proof of concept that this works, I highly suggest migrating all code toMySQLi functions rather than using this, but it provides a simple path that allows you to upgrade PHP and enough time to migrate your code base over.

In $sourcedir/Subs-Db-mysql.php Find:

Add before this:

Now find:

Replace with:

In $sourcedir/Subs-Compat.php at the end before ?> add:


This should allow SMF to run just fine.  These are all the functions SMF calls from it’s database abstraction layer and thus should work.  Anyone using mysql functions outside of SMF’s database abstraction layer may need to add in additional functions.

SFTP, SSHFS, VPN + exportFS, and WebDav.

While working on some code, I needed to get something I could access much faster and much easier than my current methods.  So after some testing, I’ve come across a solution.

I started with my simple SSH session.  This proves to not be so helpful when editing multiple files or needing to move around easier.  While the power of command line is great, it isn’t so great for developing larger scripts or moving around between multiple files easily.

So onto SFTP.  I used a sftp shelled user by adding that user to a group and forcing that group in my sshd.conf to always use sftp:

This works very awesome and is much more secure than FTP. It is using the SSh backend, which is very secure but foces it down to a ftp layer. The jailed user can’t run any commands, no forwarding, and is chrooted to a directory (their home in this case). However, this was slow. On average it would take 4 seconds to load a file. Directory listings where fairly fest (usually 1 second, sometimes 2). Unacceptable delays just to edit a file.

Since SFTP was out of the question, I figured it would be similar, but gave it a try anyways. I setup SSHFS using OSXFuse and SSHFS and then (A simple GUI to test with, if it worked I would learn to use the CLI). With that setup, it was even worse. Files would open in 1-2 seconds, but directory listings just took forever, sometimes not even loading at all.

As SSHFS was not a option and since I wanted to try it anyways, I tried to setup VPN. OpenVPN being the choice here, I spent a few hours working on setting this up. This took a bit to configure as my firewall was blocking a lot of the connections, even once I got the right port configured, the firewall still blocked access. But once I sorted out allowing that private traffic and getting the certs in the right place, I got connected to my new VPN. I will note that if you don’t sign the certificate, it doesn’t produce a valid .crt file. So make sure to say yes to that.

After setting up VPN, I needed to setup exportfs so I could export the directory I wanted. More troubles with that. A combination of the correct options on server side (rw,sync,no_subtree_check,insecure,anonuid=1000,anongid=1001,all_squash) and the right ones on the client side (-o rw,noowners -t nfs) to finally get it to work properly. Alas after all these troubles, it was the same issue as SSHFS. Slow directory loading. This was unacceptable and would not do.

Finally, tried WebDav. At first I was trying it in a directory, but my location directive for php files in Nginx was wreaking havoc. So I just setup another subdomain to deploy this under. It also appears that Nginx at least on Ubuntu 12.04 (possibly similar versions on Debian as well) has the dav module and extension (for full support) built into it. I simply just needed to setup the configuration for it. Really easy to do and didn’t take much time, I think I set that up in less than 30 minutes).

The result is great. WebDav is fast. Directory listings are almost instant and files open in just a second. While OS X (Mountain Lion) does not seem to have the correct support for WebDav and attempts to look foe resource files and other hidden files (such as a .ql_disablethumbnails which I assume is for QuickLook to not load a thumbnail). So it was over to my FTP client that supported WebDav. Wish I could of had native Finder support for it, but oh well.

A IRC user said it best though and I couldn’t agree more now: < rnowak> SleePy: webdav rocks, totally underused.

SMF on Nginx+SPDY

No surprise here as SPDY is a server side thing, SMF works no problem using Nginx+SPDY. So there should be no problem with the SPDY plugin/module at all in any other web server. Just need to set it up on your web server. Nginx currently has a patch for it. But I would suspect that this will be merged into its trunk soon and make its way to stable in Nginx.

SMF $user_info in as a class

I wrote up this method while writing my Pastebin. It was an experiment mostly to not have to use as many globals in my main code. I think it turned out nice and easy. Knowing that SMF 3.0 will use OOP does not help as this is the least likely way this would be implanted in the code. At least this can act as a bridge at that time to the new code.

I should explain the _() method. I set this up so I could do a Singleton. It also allows me to use it in a sorta static method by doing “userInfo::_()->id;”. Nice quick and easy.

I could of wrote this like my smcFunc class, but choose otherwise on the fact I wanted to use it as a object rather than a static method. A setup like that should be possible, but I didn’t test that.

I never tested but I don’t think accessing multiple dimensional parts of the $user_info will work. Things like $user_info[‘group’][1] most likely won’t work here. I should add support to drill down into the array, but will save that for a later day.

Pastebin rewrote

I have taken my original code I wrote for my SMF powered pastebin and rewrote this script. This was a massive rewrite from the original code and hopefully it works out well for anyone else who is looking into using it.

I wrote it so it should be plugable with different databases, user information and templating engines. The design was mostly to implant it into my mixed environment of SMF and WordPress, but also to make it robust so it could be used in other ways.

The source of the code is up on GitHub at

SMF in WordPress

For some reason, while using WordPress and including SMF’s SSI.php, it would not detect my logged in SMF session. Baffled and almost thinking this was a SMF bug of some sorts, I began to debug this process.

Well it turns out it is sorta a SMF old PHP support issue, but the problem lies in WordPress. This is the function in WordPress wp-includes/load.php

The problem here, is that they add magic quotes to the cookie. Not quite sure why they are even doing this. But it broke adding SMF. The part in SMF which failed because of this is in SMFs Sources/Load.php in the loadUserSettings function

Because of old PHP support in SMF, its trying to combat a cookie security issue that existed below PHP 4.3.9. Now I don’t use that version, but I rather not strip out the code. The preg match was failing because it was not finding that valid string in the cookie. Since all the double quotes where escaped with a slash \.

For my code, I called in Settings.php from SMF and then did a stripslashes on the cookie. Then I included SSI.php, with the results I expected of it finding my active SMF session.

I should note because SMF uses a lot of global variables, that I had to globalize all of those before hand. I just borrowed the globals from SSI.php and put them into that scripts function.

SMF Package Manager Generator

Originally I had wrote my original SMF Package Manager Generator a few years ago. It was sloppy coding, poor JavaScript and relied heavily on the server. Not my absolute best work, but was something I was proud on at the time from my efforts to dive into JavaScripting.

However, todays times are different. So with JQuery out there, I decided to take breaks from my projects for a couple hours for a few days and put forth a effort to rewrite this. Needless to say, I had the initial code wrote in only a few hours. My original script took me a few days alone. That didn’t count the package-info creator I made later which also took a while.

The new script attempts to rely all on JavaScripting via JQuery. It was a fun experience to build it this way. Although, because of JavaScript’s security measures, I couldn’t leave downloading the file outside of the server. So alas, I still have to process the actual download via the server. There is a work around with using Data URIs, however it didn’t provide the filename and sounds a bit flaky when the length of the url gets to be a bit long. I included both as a option though.

Oh and Its on github, because I see no reason to not share the code. Including the code I used to integrate it into my WordPress blog.

SMF poster info on right

So I am a little bored.  I decided to figure out how much css it would take to make the poster info be on the right.  Turns out, actually not that much.

float: right;
width: 16em;

margin: 0 15em 0 1em;

.post, .modifybutton
clear: left;

margin: 0 0 0 1em;

Which could be shrunk down even more, but I wanted to tweak a few things as well to perfect the fit.

Now for the fun part, we can make this a user option.

First we create a file in Themes/default/css/ and call it something like post_right.css.  It will need the contents of the css above.

Secondly, we go to Admin Control Panel -> Core Features.  Then we enable Advanced Profile Fields and save.  We can either click the link now or navigate to it from the menu.

Now we create a new field.  There is a trick here I would suggest.  For the name use “postright”.  You can fix it after you save it the first time.  This will ensure we get a column name of “cust_postri” and not something totally meaning less.  Advance Profile Fields will use the first 6 characters of the name as the column name, unless you modify it manually (ie direct database edit).

Since that is all said and done, we have to make one edit to index.template.php in Themes/default

We will look for:

// RTL languages require an additional stylesheet.

Now we will add some code to check the user option exists

// If the user wants it, put the poster info on the right.
if (!empty($options[‘cust_postri’]))
echo ‘
<link rel=”stylesheet” type=”text/css” href=”‘, $settings[‘theme_url’], ‘/css/post_right.css?rc3″ />’;

Save that and it is done.

SMF Poster Info to the right

What is even better is the fact we can make a greasemonkey script.  Now I am not an expert so I just googled how to do this.

Basically it would be something like this though:

// ==UserScript==
// @name           SMF poster to right
// @namespace
// @include*
// ==/UserScript==

function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName(‘head’)[0];
if (!head) { return; }
style = document.createElement(‘style’);
style.type = ‘text/css’;
style.innerHTML = css;

addGlobalStyle(‘.poster{ float: right; width: 16em;} .postarea{ margin: 0 15em 0 1em;} .post, .modifybutton{ clear: left;} .moderatorbar{ margin: 0 0 0 1em;}’);

It would require some configuration such as where to include it.

Here are the files css and greasemonkey files, you will need to save them to your desktop and put them in their correct locations.

post_right CSS file

smf_poster_to_right.user JS file

$smcFunc as a static method via overloading

This was more of something I wanted to play with.  I wanted to convert $smcFunc into a method.  So for instance lets say $smcFunc[‘db_quote’]() would be smcFunc::db_quote().

This wasn’t looking good at first.  I thought I could use __construct and just intercept what is going on.  But static calls do not use __construct.  So this left me thinking of how I can achieve this.  Of course I could just manually setup all functions inside a smcFunc class.  But this would be a lot of work and wouldn’t work with db_extend.

Finally I came across what I need.  It only exists in php 5.3.0+, so this isn’t a solution for everyone.  But for my sites and where this script is going to be ran, I use php 5.3.  I am using __callStatic.  Simply using that, I then just use call_user_func_array to pass it to $smcFunc

Here is all the code needed to do this:

class smcFunc

public static function __callStatic($name, $arugments)

global $smcFunc;
return call_user_func_array($smcFunc[$name], $arugments);



Really slick and gets the job done nicely 🙂

Of course the smcFunc class won’t just have that, as I have other plans.  However this is my biggest hurdle I needed to jump.  I am hoping the others will be possible as well.

Automating modification packaing

Packaging mods is not the funnest part of building any mod.  So why should I do it manually?  I run Mac OS X which means I have a terminal and can run commands directly to accomplish the packaging process.  I just needed to build a script.  Easy to do and now its done, so I will just detail out the script.

// Da mads location!
$dir = ‘/home/smf/Mods/’;

// Disallowed stuff.
$disallowed_files = array(‘.’, ‘..’, ‘.DS_Store’);

// Our Tar binary executable
$tar_bin = ‘/home/software/gnutar/bin/tar’;

So, this is some settings.  The first tells me where my mods are located.  The path after this matches what I have in SVN for my mods.  So you can put together an image of what I have setup.  The next is an array of disallowed files that we want to ignore when reading directories.  The final one is the full  path and name to the tar binary.

I custom installed a tar binary since the built in OS X adds resource forks and I did not want to break anything by replacing the built in tar with my own (I doubt it would, but didn’t feel like finding out months later and having to fix it).

// No more changes!!!

// Package them?
if (isset($_POST[‘package’]))


This has no explanation really.  It is my header, packaging code, most list and footer (to properly close all html tags 😉 ).

// List the mods!
function listMods()

global $dir, $disallowed_files;

// Get the mods.
$mods = scandir($dir);

This is the start of my mod listing.  Which I globalize the directory and disallowed files.  Then I simply perform a scandir to get a listing of all my mods.  The next section of code contains html, so I will skip that since it isn’t important.

$modOut = array();
foreach ($mods as $mod)

if (in_array($mod, $disallowed_files))


$xmlData = simplexml_load_file($dir . ‘/’ . $mod . ‘/package-info.xml’);
$modOut[strtolower($mod)] = $xmlData->name;


Now simply put, this code will simply prepare the output by doing simplexml to create an object based on the xml data, which I can then use to get the name of the mod (much easier than reading, and pulling from the file with a regex).  Finally I sort the array by the key.  Again, more html to ouptut this data.  I simply used checkboxes.

function DoPacking()

global $dir, $tar_bin;

echo ‘
Packing…<br />’;

This function does the actual work.  For this one I just need to global the directory and tar binary.

$force = isset($_REQUEST[‘force’]) ? true : false;

This simply just allows me to force a mod to be packaged even if it exists for that version.  I didn’t need anything complicated as this rarely is needed.

// This just finds what mods we want to package.
$allowed_mods = array();
if (isset($_REQUEST[‘mods’]))

foreach ($_REQUEST[‘mods’] as $in)

$allowed_mods[] = trim($in);

This simply just does a loop to find all mods I want to package.  If this was a public script, I would need to validate the input against an array of mods that exist.  But since it is just used internally, I didn’t do that.  But now we get the the actual work.

// Get em!
$mods = scandir($dir);
foreach ($mods as $mod)

global $temp_key;

if (in_array($mod, $disallowed_files))


if (!empty($mods) && !in_array(strtolower($mod), $allowed_mods))


We first start by scanning the directory again, removing the files we don’t want, this time we are removing mods we didn’t want to package from the array.

// Files in this folder.
$files = scandir($dir . ‘/’ . $mod);

foreach ($files as $key => $file)

if (in_array($file, array_merge($disallowed_files, array(‘images’, ‘releases’))))


This just puts all files inside each mod folder into an array and removes the files/folders we do not want to package.  I use the same structure for all my mods, so I don’t have to worry about individual cases.

// Figure out our version, the first match is our keeper!
preg_match(‘~version\s+([\d\.]+)(^\S+)?~i’, file_get_contents($dir . ‘/’ . $mod . ‘/Readme.txt’), $matches);

I don’t usually update the version in my .xml file, only my readme.  So I need to get the latest data from my readme file.  This is going to be used to update my version info in multiple places.  The next part is more html, so I am skipping it again.  It basically is checking for existing versions of missing versions and letting me know.

// Update all version information.
foreach ($files as $file)

if (substr($file, -4) != ‘.xml’)


$new_contents = preg_replace(‘~<version>([^<]+)</version>~i’, ‘<version>’ . $matches[1] . ‘</version>’, file_get_contents($dir . ‘/’ . $mod . ‘/’ . $file));

// Null is ugly!
if (!is_null($new_contents) && !is_array($new_contents))

file_put_contents($dir . ‘/’ . $mod . ‘/’ . $file, $new_contents);


Now I simply loop through all files, looking for the .xml ones, as these have a version tag in them.  Once I located them, I simply update them with the new version.  Prior to updating the file, I make sure nothing went wrong.

// Change our directory.
chdir($dir . ‘/’ . $mod);

// Tar it!
// ZIP: zip -0XT ../ ./* -x .svn
exec($tar_bin . ‘ -czf releases/’ . $mod . ‘_v’ . $matches[1] . ‘.tgz ‘ . implode(‘ ‘, $files));

Now for the actual fun stuff.  Prior to packaging the mod, I need to change to the directory.  This prevents a path of folders when the mod is unpackaged.  Then finally I run the command to package the mod.  I have it automatically package it into the releases folder based on the mod name, and its version and explicitly name all files I want to package, thus avoiding disallowed files.

That is all the actual work to handle the packaging.  I haven’t tried it yet, but I added code with theoretically should allow this script to work from CLI.

// Not used yet, but can handle cli stuff.
function handle_cli()

if (in_array(‘force’, $_SERVER[‘argv’]))

$_REQUEST[‘force’] = true;

foreach ($_SERVER[‘argv’] as $in)

if (in_array($in, array(basename(__FILE__), ‘–‘, ‘force’)))


$_REQUEST[‘mods’][] = trim($in);



Someday I may actually test the code, but oh well for now.   The final bit is more html for the header and footer.  So that is all the code I need.

Download: modpacking.php (Right click and save file)