[PHP] Sitemap generator for directory listing

Sitemaps are lovely, aren’t they? Not so easy to generate (or *gosh* make manually). Being a programmer, I decided to write a little PHP script to generate one on the fly for a massive (almost 3,000 files) downloads site that I host for gamers. There’s a download link attached to this post, but here’s a look at the code from above.

It has one dependency of phpURI which I use to generate the links for urlset:url::loc elements in the XML. It also uses PHP’s XMLWriter to generate the actual XML for the sitemap.

// BEGIN CONFIG OPTIONS
$default_change_freq = 'monthly';
$url_prefix = 'http://downloads.cncfps.com/';
$blacklist = array('cgi-bin');
// END CONFIG OPTIONS

require_once(realpath('../phpuri.php'));

$filter = function($info, $key, $iter)
{
    global $blacklist;
    if (preg_match('/^..*/', $info->getFilename()))
    {
        return false;
    }

    if($iter->hasChildren() && !in_array($info->getFilename(), $blacklist))
    {
        return true;
    }

    return $info->isFile();
};

$dirall = new RecursiveDirectoryIterator('./', RecursiveDirectoryIterator::SKIP_DOTS | RecursiveDirectoryIterator::KEY_AS_PATHNAME);
$dir = new RecursiveCallbackFilterIterator($dirall, $filter);
$files = new RecursiveIteratorIterator($dir);

header('Content-Type: application/xml');

$writer = new XMLWriter();
$writer->openURI('php://output');
$writer->setIndent(true);
$writer->startDocument('1.0', 'UTF-8');
$writer->startElementNS(NULL, 'urlset', 'http://www.sitemaps.org/schemas/sitemap/0.9');

$writer->startElement('url');
$writer->writeElement('loc', phpURI::parse($url_prefix)->join('sitemap.xml'));
$writer->writeElement('lastmod', date(DateTime::W3C));
$writer->writeElement('changefreq', 'always');
$writer->endElement(); // <url></url>

foreach($files as $file => $object)
{   
    $writer->startElement('url');

    $furi = phpURI::parse($url_prefix)->join($file);
    $furi = htmlentities($furi, ENT_COMPAT | ENT_XML1); //$furi = rawurlencode($furi);

    $writer->writeElement('loc', $furi); // <loc></loc>
    $writer->writeElement('lastmod', date(DateTime::W3C, $object->getMTime())); // <lastmod></lastmod>

    // TODO: read filename.ext.txt for metadata
    $writer->writeElement('changefreq', $default_change_freq); // <changefreq></changefreq> 

    $writer->endElement(); // </url>
}

$writer->endElement(); // </urlset>
$writer->endDocument(); // EOF
$writer->flush();

exit;

Right now, it generates the sitemap on the fly, and only lists files found in the current directory (recursively). I do have plans to add support for per-file configuration (perhaps even per-directory configurations) via “filename.extension.txt” to change things like changefreq and priority per-file.

If you want to change this to run as a cron script, simply change $writer->openURI('php://output'); to $writer->openURI('sitemap.xml'); and it will write the sitemap out to a file (note, appropriate server permissions for writing are needed). If you do this, be sure to remove the sitemap.xml entry from the script.

Of course, if you use on the fly generation, you’ll probably want to use URL rewriting to map /sitemap.xml to /sitemap.php instead. The following is the Apache .htaccess config for such.

<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteBase /
    RewriteRule ^sitemap.xml$ sitemap.php [L]
</IfModule>

Download: sitemapgen.zip

Science Fiction – Exploring who WE are

Science Fiction – Exploring who WE are

Perhaps my favorite quote of all time (so far) comes from a scene in Star Trek: Enterprise when Ambassador Soval and Admiral Forrest are entering the Earth embassy on Vulcan. They are discussing the perception of Humans by Vulcans.

Soval: “We don’t know what to do about Humans. Of all the species we’ve made contact with, your’s the only one we can’t define. You have the arrogance of Andorians, the stubborn pride of Tellarites; one moment, you’re as driven by your emotions as Klingons, and the next you confound us by suddenly embracing logic.”

Forrest: “I’m sure those qualities are found in every species.”

Soval: “Not in so confusing abundance.” Forrest: “Ambassador, are Vulcans afraid of Humans?”

Soval: *nods*

Forrest: “Why?”

Soval: “Because there is one species you do remind us of.”

Forrest: “Vulcans.”

Soval: “We had our wars, Admiral, just as Humans did. Our planet was devastated, our civilization nearly destroyed. Logic saved us. But it took us almost 1500 years to rebuild our world and travel to the stars; you Humans did the same in less than a century. There are those on the High Command who wonder what Humans will achieve in the century to come and they don’t like the answer.”

Forrest: “We’re not the Klingons. We only want to be your partners, to do what the nations of Earth have learned to do: To work together in common cause.”

Soval: “Unfortunately, the future of relations between our two worlds is not mine to control.”

It really opened my eyes to what Star Trek represents, as well other science fiction shows such as the Stargate series. These science fiction entertainment shows help us to understand ourselves by putting us in front of a mirror to analyze our own behavior. I think this quote explains that perfectly and I hope your outlook on these shows changes as it has mine.

Self-install/Self-setup PHP Installation

Recently, I decided to give IIS another try in preparation for learning the WCF Framework. I also decided to try PHP as well with IIS (7.5 in this case).

Unfortunately, I ran into some issues with installation as I tried to install PHP 5.4 along with IIS. The actual installation and use of PHP worked, however, I couldn’t figure out why PHP was looking in “C:WINDOWS” for my php.ini, rather than the actual directory where I (then) extracted PHP to. I noticed later, when I downgraded to 5.3 since it had an installer available, rather than just a .zip download.

If you are setting up PHP with IIS, manually or via installer, you need to log the HTTPd’s account out of Windows and back in again. The issue mentioned above is PHP is looking for “php.ini” in “C:WINDOWS” which is undesirable. The PHP 5.3 installer edits your Windows PATH environment variable to include “C:PHP” (or wherever you installed PHP). Windows doesn’t associate this change until you logout and log back in again.

If you happen to install it manually, edit your path variable to include your PHP directory. See the screenshot for other details that would be useful.

This was done on Windows 7 Professional, 64-bit.

array_walk Usage

Alright, so I was confused by the PHP Docs on array_walk. So, I wrote a little example to try to figure out how it works. I did so because the PHP documentation on the function was a bit unclear in my opinion.

The basic structure for array_walk is:

array_walk( array $myarray, function(&$val, $key) );

That said, you can see my usage here and the corresponding output it provides.

WordPress Theme & Javascript Bloginfo

Alright, I’m pretty sure this has been done before.

Scenario: I need to access bloginfo() function from inside a script block on my custom theme.

Solution (partial): A partial solution to this is easily remedied with minimal code. However, this solution only allows default bloginfo() to be retrieved.

The following function goes inside your theme’s functions.php file:

function get_the_bloginfo_array()
{
    static $_bloginfo = array( 'name', 'description', 'admin_email', 'url', 'wpurl',
                        'stylesheet_directory', 'stylesheet_url', 'template_directory', 'template_url',
                        'atom_url', 'rss2_url', 'rss_url', 'pingback_url', 'rdf_url', 'comments_atom_url',
                        'comments_rss2_url', 'charset', 'html_type', 'language', 'text_direction', 'version' );
    $jsArray = array( );

    foreach ($_bloginfo as $key)
    {
        $jsArray[$key] = get_bloginfo($key);
    }

    return json_encode($jsArray);
}
var bloginfo = <?php echo get_the_bloginfo_array();?>

 

 

TeamSpeak 3 Server on Debian Squeeze

UPDATE: 2012.12.23 – Updated package links for x86 and x64 packages.

UPDATE: 2015.02.19 – As of a few patches ago, TeamSpeak 3 now linked against the correct MySQL binaries.

Well, I due to a recent run of bad luck on my current VPS host, I was forced to go looking for a new server. I found one to which I was referred to by another customer and a friend of mine—the host is known as NFO Servers.

Anyway, when I finally got the server setup enough to be able to start setting up individual servers on it, I got the MySQL Database all setup and configured in my TS3 server config files…I kept getting the following error:

INFO    |DatabaseQuery |   | Please make sure you use the supplied ts3server_minimal_runscript.sh to run the server, or set LD_LIBRARY_PATH yourself CRITICAL|DatabaseQuery |   | unable to load database plugin library “libts3db_mysql.so”, halting!

I searched on the Google for answers and found some random and unhelpful posts from TeamSpeak 3’s Official forums – though, they were slightly helpful, but weren’t specific enough to provide a one-stop solution.

The problem as stated in this forum thread is as follows:

TeamSpeak uses libmysqlclient.so.15 but Debian Squeeze serves libmysqlclient.so.16.

“No problem, right? Just do what he says to do in the next line and you’ll be all setup.” — Nope. For those of you who are sort of new to Linux, like myself, you don’t know what “the old Lenny repository” is that he’s talking about. I tried to find the repository from the Google again, but to no avail, I tried the next best thing: Installing the package via wget and dpkg directly, and, Voila! It worked!

Download one of the following packages (based upon your distribution):

Example:

wget -O libmysqlclient15off.deb http://archive.debian.org/debian/pool/main/m/mysql-dfsg-5.0/libmysqlclient15off_5.0.51a-24+lenny5_amd64.deb

In the same location of wherever you are currently when you downloaded the package,

mv libmysqlclient15off_5.0.51a-24+lenny5_i386.deb libmysqlclient15off.deb
dpkg --install libmysqlclient15off.deb

And this will install the missing dependency for your new TS3 server.

If my post is unclear in any instructions, drop a comment and I’ll try to explain it better for future people. Thanks for reading!