Category: General

$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.

Removing everything other than .svn

After I updated some code, I was downloading it into my local svn repository and planned to do a svn commit.  I thought I had set my FTP settings correctly to merge folders, but alas I didn’t.  What I ended up with was a broken svn working copy.

So I decided to pull another checkout in another directory.  After doing that, I needed a way to just get the .svn folders and its files out.  The quickest method I could think of would be to use my FTP client (Transmit by Panic) and this time merge the folders together.  I am sure there is a better way but I didn’t have much time to waste searching.

To accomplish this task, I needed all other files removed.  So I wrote a function to do this:

—–

function remove_non_svn($dir)
{

$files = scandir($dir);

foreach ($files as $file)
{

if ($file == ‘.’ || $file == ‘..’ || $file == ‘.DS_Store’ || $file == ‘.svn’)

continue;

if (is_dir($file) && $file != ‘.svn’)
{

remove_non_svn($dir . ‘/’ . $file);
rmdir($dir . ‘/’ . $file);

}

else

unlink($dir . ‘/’ . $file);

}

}
—–

Then I just popped that into a script and told it what folder to execute this on and it went to work.  It quickly did the job and got it all cleaned up.  Then I simply used my FTP client to merge the folders into the working copy.  After that a svn status showed the modified copies and was working.

I should note that doing this is dangerous to your svn working copy and could break things if not done right.  There also may be better methods to restore you working copy to working order.  I just didn’t have much time on my hands to search for it.

Mysql queries using offsets without limits

While working on a project, I came across the need for a script to run a loop through a table and process some commands.  However, due to the size of the table, this surely would take longer than the default 30 seconds that is setup in most configurations.  However, I didn’t want to do any limits.  I wanted my script to determine when it was nearing the timeout and then stop, otherwise try to process more.  So a standard LIMIT in mysql wouldn’t do it.

Much to my surprise, MySQL doesn’t offer a way to just do a OFFSET.  You have to use the LIMIT with OFFSET or none at all.  This was really annoying as I thought I would have to go back to limiting the query size.

Well, then I realized, that this could be solved another way.  I just added a column and populated it with an incremental numbers.  Then I told my script to ORDER BY that column id using ascending.  Now with that in play, I simply just added a WHERE to my query and told it not to do anything below a certain id.  The certain id comes from a variable that is passed from the user and cleaned up (safety first!).  The script after processing the needed commands, updates this variable.  Finally when it is time to pause the script so it doesn’t time out, that variable is sent with the forwarding url.  This method allows the script to pick up where it left off again when it starts up.

Seems like a very simple work around, although if I didn’t have the id column, it wouldn’t of worked.

Adobe with McAfee

I have another rant.  This time it is Adobe who has ticked me off.

I rarely use Firefox or any web browser on my windows machine.  Mainly it sits there and has Windows Media Center full screen so I can watch TV.  Tonight I had to use Firefox on my windows machine.

Firefox prompted for the 3.6.6 upgrade (I was still at 3.6.4).  So I went ahead and installed the update.  After the update, Firefox update page warned me that my Adobe Flash plugin is outdated and I should update it.  I clicked that link and then the install link.  The standard extension window came up and I waited the 3 seconds.  I didn’t get why it was doing it via an extension, I thought this is how the update would be done.  The name was Adobe download manager.

To my surprise, after FireFox restarted, it proceeded to download and install some McAfee stuff onto my machine and then failed when it tried to install the plugin update.  So it failed to do what I originally wanted it to do and installed some additional stuff I didn’t even need nor want on my computer.  Again, just like with Google Chrome, I was not prompted or given the chance to opt out of this.

That software only lasted about 30 seconds on the machine, I quickly went into control panel > Program and Features and removed that software.  I am really annoyed yet again, software is being installed on my system.  It has done one up on Google Chrome by at least telling me it is installing it.  However without the option to not install it, it is forcing useless junk onto my machine.

I am not the only one with this issue, googling “Adobe firefox extension installed mcafee software” returns numerous results.  I have to say to the software companies, I do not want stuff on my machine installed secretly or forcefully.  I only want to install the stuff I want to install and not any 3rd party or affiliates software.

I truly should go the Apple route and remove Flash from all my systems.  YouTube is already HTML5 compliant and other sites will follow for non smartphone pages.  So it isn’t like I can’t live without Flash being installed on my system.  Maybe I will do that.

On the last note, I removed Flash, restarted firefox, and got the missing plugin notice.  I simply clicked the missing plugin notice, downloaded the Flash plugin and now flash is updated on my system.  If I don’t remove Flash from my system, I am going this route from now on to install all updates.

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!!!
Warp_header();

// Package them?
if (isset($_POST['package']))
doPacking();

listMods();
Warp_footer();

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))

continue;

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

}
ksort($modOut);

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 ‘
<div>
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))

continue;

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

continue;

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’))))

unset($files[$key]);

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’)

continue;

$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 ../path_name.zip ./* -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’)))

continue;

$_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)

SimpleDesk Download Manager

For the SimpleDesk website, I made a very easy to use and very sleek download manager.  Complete with branch, version, file and mirror management.  Simply put, this thing is very powerful and flexible.  While I didn’t add it in, I could easily expand this script to manage multiple pieces of software as well.

Moving mysql

Time to move my mysql data directory to another drive.  So its up to some simple commands to get me started.

First my my.conf file.

$ sudo mv /etc/mysql/my.cnf /home/configs
$ sudo
ln -s /home/configs/my.cnf /etc/mysql/

I should note that the way I installed mysql (apt-get), a debian.cnf file is created.  I haven’t even bothered to see if this file is actually used by ubuntu.  But none the less I need to copy it as it contains a mysql user/password for use by the system.  Which isn’t really safe considering it is a root account.  Setting open_basedir restrictions help with that though. As well in the mysql.conf folder a mysqld_safe_syslog.conf file exists, I don’t use safe mode so I don’t care about it.

$ sudo mv /etc/mysql/debian.cnf /home/configs
$ sudo ln -s /home/configs/debian.cnf /etc/mysql/

Now for a quick test, I restarted mysql via the restart command.  Very helpful command and is easier to type then using init.d

$ restart mysql

Everything still works.  So now for the final touch.  Moving the directory.

$ service mysql stop
$ mv /var/lib/mysql /home/data
$ ln -s /home/data/mysql /var/lib
$ service mysql start

Now I won’t lie, at this point something went horribly wrong.  I have yet to figure out why.  I have done this many times before and never had an issue.  After trying everything I could think of to get mysql started, get rid of the errors and even moving it back, I still had no luck.  I ended up restarting the entire box and after that things just worked.  So I tried again and then everything worked just fine the second time around.  I have no clue why it failed the first time.

Just to add a finishing touch, I edited the /home/configs/my.cnf and changed datadir in it to point to /home/data/conf

That takes care of that.  Next is to figure out all the configuration files I need to duplicate over for my mail setup.  Hopefully after all that, my web site should be able to easily switch from ubuntu to another operating system and be up and running in no time.

Securing database user credentials

A random thought has hit me.  Most people try to keep their MySQL user credentials secure.  But why?  If a server has been setup properly, it becomes a mute point.

The idea occurred me when thinking about opening a sites source code up.  If I opened the site up, I could give them access to my settings and configuration files.  These files also contain mysql user credentials.  So either I attempt to remove those, or I disallow access.  However, I then wondered why even worry.

I will use my own site as an example.  If I give out my MySQL user credentials to my inactive forum, what good would it do someone?  phpMyAdmin is secured behind a HTTP_AUTH page (over SSL) before you can supply the MySQL user credentials.  I have configured all my MySQL users to only allow localhost connections, so only connections from my server alone are allowed.
So if somebody had my MySQL user credentials, they would be completely useless.  If they managed to exploit the server and upload files that do malicious stuff, they would most likely be able to have that script find and read the settings file.  That being if it was somewhere in the open_basedir restrictions for that site.  If they managed to exploit the server, they could do more damage then logging into mysql.  Although since only I have a login to my site (secured behind SSH),  I have very few files that apache can edit or write to that is web accessible.  To fix any mysql damage they did, all I need to do is restore all mysql data (users as well) from a backup.  File damage is much worse as it is easier to leave a backdoor into the system then.

Although I don’t run any control panel and use phpMyAdmin simply for ease of access, other sites that run admin panels such as cPanel also apply.  Unless they have the cPanel login information, the user installed phpMyAdmin for some reason or configured their mysql users to have outside connections, the data is useless.  With the exception being if an attacker was able to upload a malicious file

For shared servers, this could be a worry if your MySQL credentials are publicly known and a hacker happens to also have a site on your shared server.  So my above points will have little value if your server is shared.  Shared servers carry a risk and that risk means attempting to protect all your credentials more heavily, as an attacker could simply be on the same server as you.

Of course this all depends on the server admin and webmaster having properly setup things such as access to phpMyAdmin and other scripts before hand.  However I think this still provides a good point that even if MySQL credentials are publicly known, they still don’t offer much.

Applications hidden addons

Like all good conversations, this was brought up in IRC.

http://www.theregister.co.uk/2010/06/11/microsoft_slips_firtefox_add_on_into_software_update/

Microsoft decided it would be a good idea to install a hidden addon to firefox installs for those who have some services installed.  The major point being it is a hidden unknown addon that you can not remove yourself.  How friendly is that?

Google’s Chrome does the same thing.  After first running it, I discovered that it installed a hidden service to my user’s Application Support (Mac OS X) folder.  I ran a few commands as root to remove the file and chmoded it to “0000″.  I also removed Chrome as well and checked all files it modified.

Other than being totally shocked that Chrome is installing a service without my permission, I am questioning continuing to use any of google applications now.  This would of all been ok, if Google Chrome had asked for permission to install a service that supposedly “checks for updates”.  Of course I wouldn’t of allowed it anyways, I have enough services running on my poor laptop and I don’t need to add a useless one.

Hopefully both Microsoft and Google get it straight.  Although I can’t say much about Apple who forces you to install QuickTime and Apple Update on windows.  So maybe all three need to get a clue.  I want to know what you are doing to my system.  Keeping this up will only make me move to full time linux usage more and more.

As a quick end note.  Procrastination paid off, as I haven’t run windows updates in about 2 weeks.  Just goes to show that sometimes procrastinating can be a good thing.

Moving home directory to a new drive

My current host has a unique feature in which it allows me to setup virtual machines easily. Since that is easily possible, I may want to someday switch to another operating system. So I wanted to split all my /home and configuration files out onto a separate drive. Which is entirely possible with my host.

The nice thing about linux systems is since they operate on open source software, things like configurations and setting things up are becoming less of a problem.  So If I set up my files correctly and use some correct symlinks, I could easily switch my operating system without missing a beat.

I will avoid discussing the details of getting the other drive setup on my machine. However, getting to working properly does take a little bit of work, all of which is easy.

Firstly, after I made sure the new drive exists in /dev, I simply created a folder to where I would mount the files.

$ mkdir /home-new

Now the directory exists, I simply just mount the drive to the directory.

$ mount /dev/xvdc /home-new

Doing some basic commands, I tested to ensure that the drive works and is functioning properly.  The next step involves copying files over.  However I had my site setup with permissions already and copying them would result in them being owned by root again.  Luckily the copy command has a argument that allows us to preserve that.

$ cp -Rp /home/* /home-new

Once that completed, I ensured that the files all worked on the new drive.  Next was to edit my /etc/fstab so the drive would mount correctly on reboots.  Simply put, I just copied the one for my root drive, changed the /dev device to the correct drive and the mount point to /home.  Just incase something went wrong, I shut off apache and moved /home to /home-old with a move command.

Now, I could of easily umount the /home-new drive and remount it on /home.  But just to ensure everything worked, I issued a reboot command and waited for my server to reboot.  After the reboot, I was able to see my site working again.  However I was not done yet.  My apache configuration files are still on the main drive.  An easy way for me to get around this is moving all my virtual host configuration files to my home folder and creating a symlink to them.

$ mkdir /home/configs
$ mv /etc/apache2/sites-available /home/configs
$ ln -s /home/configs/sites-available /etc/apache2/sites-available

This completes the move of my apache configs.  I modified the default configuration and have it containing things like port and other apache configuration changes.  I just simply repeated this for other configurations I changed and wish to have them transfer if I switch operating systems.

The only thing left to do is change where my mysql data is being stored.  Although I will work on not breaking that the first time around some other day :)

Dansette