New chance for crashed (port 3307) db4free.net server

One month ago I set up a new MySQL 5.5 db4free.net server instance, after the old instance started to keep crashing. Since then, the former user database server has run on port 3307 to give people a chance to rescue their data, while the new MySQL 5.5 instance started completely from scratch.

However, most of the time, the 3307 server was down and I doubt that many people had a chance to get a copy/backup of their data. Now I updated that server to MySQL 5.5 as well. It’s too early to tell whether or not that will increase people’s chances, but it may be worth to give it a new try.

db4free.net is back again, with MySQL 5.5

Disaster struck again. Well, it’s actually not really a disaster. db4free.net is a testing environment and people are not supposed to use it for any important data, or to use it in production. When after the last server update the main server instance started crashing, it was one of these circumstances which I can’t guarantee my users not to happen, and since both my budget and the server resources are low, I can’t afford setting up a backup system which allows me to restore everything just as a commercial database provider can (or should be able to) do.

Unfortunately I received a few emails (sorry that I couldn’t answer all of them directly) which made me believe that this fact isn’t obvious to all users. Even though the Conditions of Use pretty much explain that, not everybody obviously reads them. Which is why I added this text to both the registration form and to the registration email, so that it leaves no doubt that every db4free.net user is aware that this service is good for testing, but NOT for any data which is painful for the user to lose, or to not have available if the service goes down:

By registering for a db4free.net account you agree that:

  • db4free.net is a testing environment
  • db4free.net is not suitable for production
  • if you decide to use your db4free.net database in production despite the warnings, you do that at your own risk (very frequent backups are highly recommended)
  • data loss and outages can happen at any time (any complaints about that will likely be ignored)
  • the db4free.net team is not granting any warranty or liability of any kind
  • the db4free.net team reserves the right to delete databases and/or accounts at any time without notice

Sorry if I failed to make this clear enough in the past. Please note that these are no rule changes, but only a more thorough clarification.

OK, so now to the changes. After my InnoDB tablespace recovery attempts failed, it was clear that I need to set up a new server instance. Being a testing environment, it’s not really meaningful to use the now very mature MySQL 5.1 builds. So it’s time for an update, to MySQL 5.5, which is currently available as version 5.5.7, which is a Release Candidate (the last stage before becoming a Generally Available version).

Running a development version of course increases the chances of crashes and outages additionally, so it’s a good time to remember all users of the purpose of this service. This new server instance is fresh and new, no databases have been transferred and all users will have to register again to create a database.

What happens with the former 5.1 server instance? As it still starts up, I will keep it running until at least the end of November (unless anything else happens, the no-guarantee-rule keeps applying), on port 3307. So all former users can still access the database and try to rescue data they need. Please understand that I can’t offer any individual support for this. Please refer to the MySQL Reference Manual if you need assistance. You can also still use phpMyAdmin: go to http://www.db4free.net/phpMyAdmin/ and select “db4free.net:3307” from the Server Choice dropdown. However, please keep in mind that this server is damaged and will likely crash frequently, and take some time to come up again.

I am sorry for any inconvenience that the recent issues have caused. However, I am confident that this is taking the right steps to make all users aware what the purpose of db4free.net is and to set expectations right. And to all future db4free.net MySQL 5.5 users I would like to say: happy testing!

Don’t blindly rely on your sources when observing

Today was not a perfectly clear night, but good enough for some observations. Recently I found that the asteroid 6 Hebe is approaching opposition and therefor makes a good observation target, so I tried my luck finding it.

The source which I used was http://www.heavens-above.com/MinorPlanet.aspx?desig=6. The position where 6 Hebe was specified to be was RA 0h 30.6m, DE -14° 25′ (J2000). I fired up Stellarium (of all astronomical software that I know, Stellarium resembles what one can really see through binoculars or scopes the best), looked up this position, tried to find a path how to find this position (the star Diphda was a great starting point, it was easy to hop to 6 Hebe’s position from there), and searched this spot with my binoculars. Thanks to Diphda it didn’t take me long to find it.

But whoops, where I expected to find 6 Hebe, there was nothing. Instead, just a little bit further to the left there was an object just as bright as 6 Hebe was supposed to be, and according to Stellarium, there was no star of this brightness at this place. So was this 6 Hebe? I pretty much thought this has to be 6 Hebe, but it was basically just a guess, I had no evidence to support this.

What could I do to know for sure (or at least as sure as I can be)? I remembered NASA’s HORIZONS Web-Interface which allows to track basically every solar system object which is known. There I found that its supposed position is RA 0h 31.47, DE -14° 21′ 11.8″ (J2000). I checked this spot in Stellarium, and voilà – that was exactly where I saw the object which I thought must be 6 Hebe. Evidence enough to confirm.

See this Stellarium screenshot to see the discrepancy:

On the right end of the blue bar is the spot where I expected 6 Hebe to be, on the left is the spot where I actually found it. So the discrepancy is around 20-25 arc minutes, or ~ 2/3 of the diameter of the Moon.

My web-based observatory images (Pluto, Jupiter, Saturn, Uranus, Orion Nebula)

There are some web-based observatories which allow normal people like you and I to rent a telescope somewhere on this planet for a short period of time and quite reasonable amount of money, to take some pictures. Not only is the available equipment superior to the scopes that many people have at home (at least to me this applies for sure), these scopes are most often located on very favorable places up on a mountain, far from city lights and likely good weather conditions. One of these web-based observatories is Global-Rent-a-Scope or short GRaS, where I made my first steps.

They have telescopes in Australia (which adds another advantage: you can take pictures of the Southern Sky, even if you live in fairly high Northern Latitudes; this is also true the other way around of course), Spain (this one is relatively new) and the one which I’ve been using for my tests so far, Mayhill, New Mexico at 32° 54′ 3.60″ N, 105° 31′ 26.41″ W.

My latest achievement was to take 2 images of dwarf planet Pluto, the first on August 23, 2010 at 05:25 UTC and the second on August 27, 2010 at 03:11 UTC. I cut the images to show the same area of the sky, so you can open the images in new browser tabs, switch back and forth between them, and I think you should be able to spot the “pixel” which is Pluto that has changed its location significantly, while the surrounding stars stay at the same positions:

pluto-gras-20100823052500  pluto-gras-20100827031100

If you didn’t manage to spot Pluto, here is the same sky area with Stellarium (an awesome piece of astronomical software … Open Source and available for all the major platforms):

pluto-stellarium-20100823052500  pluto-stellarium-20100827031100

You can also view the original Pluto image of August 23 and the original Pluto image of August 27. The unedited Stellarium screenshots are also available, for August 23 and August 27.

This is something which I could never do with the binoculars and the telescope which I have at home. Pluto, with a magnitude of around 14, is beyond my capabilities (whether it's limited by my technical capabilities or just my skills is yet to be found out).

Here are some more images which I have taken through scopes provided by GRaS (all in Mayhill, NM).

Orion nebula on March 29, 2010 at 4:06 UTC

orion_nebula-gras-201003290406  orion_nebula-stellarium-201003290406

Saturn on March 29, 2010 at 8:52 UTC with Saturnian moons Titan, Enceladus, Dione and Rhea visible

saturn-gras-1-201003290852  
saturn-gras-2-201003290852  saturn-stellarium-201003290852

Jupiter on August 20, 2010 at 5:09 UTC with Jovian moons Callisto, Io, Ganymede and Europa visible

jupiter-gras-201008200509  jupiter-stellarium-201008200509

Uranus on August 20, 2010 at 6:35 UTC with Uranian moons Titania, Umbriel and Oberon visible

uranus-gras-201008200635  uranus-stellarium-201008200635

How to do user language/locale detection quickly without Zend Framework

Recently I wrote about detecting the preferred language or locale of a web site visitor, using Zend Framework.

Well, I have to start with one correction. In my last blog post about this topic I talked about the User Agent String, but since I wrote the article, I figured out that the User Agent String doesn’t play any role at all. Neither in the Zend Framework variant that I blogged about earlier, nor in today’s code. And that is good so, because both Internet Explorer and Mozilla Firefox will no longer add the browser language or locale to their User Agent Strings in the future. Other browsers are likely to follow, since there are efforts to make it harder to fingerprint users by their UA-Strings.

So here is my ZF-less variant:

$m = array();
$http_accept_language = 
   isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? 
     $_SERVER['HTTP_ACCEPT_LANGUAGE'] : 
     "";
preg_match_all('/([a-z]{2})(?:-[a-zA-Z]{2})?/', 
               $http_accept_language, 
               $m);

$pref_locale = array();
foreach($m[0] as $locale) {
    $pref_locale[] = $locale;
}

$pref_lang = array();
foreach($m[1] as $lang) {
    if (! in_array($lang, $pref_lang)) {
        $pref_lang[] = $lang;
    }
}

The array $pref_locale will contain all locales in order of the user’s preference, and $pref_lang will only contain the languages in order of the user’s preference. Other than my ZF code from last time, this allows to look up secondary, tertiary etc. choices of the user as well.

Here is an example. Lets assume, these are the user’s preference settings:

$_SERVER['HTTP_ACCEPT_LANGUAGE'] would contain:

en-us,en;q=0.9,de-at;q=0.7,de;q=0.6,es-es;q=0.4,es;q=0.3,ja;q=0.1.

After running my code, the $pref_locale array would contain this:

Array
(
    [0] => en-us
    [1] => en
    [2] => de-at
    [3] => de
    [4] => es-es
    [5] => es
    [6] => ja
)

and the $pref_lang array would contain

Array
(
    [0] => en
    [1] => de
    [2] => es
    [3] => ja
)

Still simple enough, and most importantly, still a better solution than what Google still does.

Running multiple Firefox versions & profiles at the same time

Oh my freaking Flying Spaghetti Monster!

I used to think that I know Mozilla applications like Firefox and Thunderbird quite well.

Now I’m wondering, how could I miss this feature that I’ve been wishing for so long? And actually, it was very near the top of my most wanted features that I wished Mozilla would implement. Today I found out, it’s been there for many years.

It is, as the subject says, to run multiple versions of Firefox, or Thunderbird, at the same time. Especially at times like these, as Firefox 4.0 is baking and becoming increasingly suitable as a day-to-day browser, while still having a few flaws which sometimes want me to refer back to version 3.6, this may be extremely useful.

However, even if you have 2 versions of Firefox installed. As long as one version is running, and you try to start an instance of the other version by just starting Firefox the “normal way”, you get a new window of the version which is already running. But there is a solution.

And it’s very simple. It’s important to have different profiles as well (this is something that I would recommend anyway, never run different versions on the same profile – it can get pretty messed up). They are easy to create, just start Firefox (or Thunderbird) with

firefox -P


I always leave one “naked” profile which I used to call “virgin” 😉

So you need at least 2 profiles. Lets assume we have a profile “ff36” to run Firefox 3.6 on and one profile “ff40” to run Firefox 4.0 on. How to start them? Here is what it could look like (assuming we have Firefox 3.6 in /opt/firefox-3.6 and Firefox 4.0 in /opt/firefox-4.0b4):

/opt/firefox-3.6/firefox -P ff36

This is basically the standard way of starting Firefox with a specific profile. Now lets start the Firefox 4.0 instance:

/opt/firefox-4.0b4/firefox -P ff40 -no-remote

Notice the -no-remote? This is the little piece that does that trick. Without -no-remote you would have gotten just a new Firefox 3.6 window. With it, you get a nice Firefox 4.0 side by side your Firefox 3.6. And here’s what it looks like:

The same works for Thunderbird as well, and probably for most or even all XUL-based applications (SeaMonkey, Songbird, Instantbird are a few that spontaneously come to my mind).

The shocking thing to me was that it has already been introduced in Firefox 2, as the MozillaZine Knowledge Base article told me.

db4free.net’s 5th birthday

To my shame I must admit, I missed it. It happened on June 29, 2005 when db4free.net was first available to the public. At that time it was running MySQL 5.0.7 beta. Quite a lot has happened since then, MySQL 5.0 made its way up to 5.0.91 and the current MySQL GA version is 5.1.49, which is also the version db4free.net is running as of today. The first phpMyAdmin version that db4free.net was offering to provide easy access to the user’s databases was 2.6.3. Today I updated phpMyAdmin to 3.3.5.

Statistics are not necessarily 100 % accurate, but here is the best I can come up with. Since its launch, db4free.net had 528,900 visits. The ratio registrations per visits is at about 22 %, so more than every fifth visit ends in signing up for a new database. Which means, that about between 110,000 and 120,000 database accounts (meaning database and user) have ever been created. There have been some cleanups since then to make resources available to people who actively use their databases. Which is why the current number of databases is much lower, at slightly above 13,400.

Today I must (also) admit that the code behind db4free.net’s web application was initially quite poor and it stayed poor for quite long. Why it was poor from my today’s point of view is probably due to my learning process in these 5 years. This year I did a lot of cleanup on the code behind db4free.net’s web application and removed a few bottlenecks which often made the website painfully slow. Now it’s in a fairly reasonable state again, and I have some ideas in the back of my head how to further improve it. So db4free.net is far from its end of life. Quite the opposite is the case, it’s time to give it a new boost so that the balance after its 10th anniversary is even more impressive than today’s 5 year balance.

Smarty 3 and __autoload()

When I first tried out Smarty 3 (which is available as Release Candidate 3 at the moment), which was that I updated an existing Smarty 2 installation, I ran into this error message:

Fatal error: Class ‘Smarty_Internal_Template’ not found in lib/Smarty/Smarty.class.php on line 444

I started to investigate what the problem may be and soon found out that libraries in Smarty/sysplugins/ were not loading. So I picked up my already existing __autoload() function and added the following code:

function __autoload() {
  // other stuff that had been here before

  if (substr($classname, 0, 15) == "Smarty_Internal") {
    $classname = "Smarty/sysplugins/" . strtolower($classname);
    require_once $classname . ".php";
  } 
}

With this addition, Smarty 3 worked perfectly, but I still kept wondering why I had to tell my autoload function explicitly to load the Smarty_Internal libraries. I found it quite ugly that I had to add it myself.

So I asked in the Smarty forum and here is why: Smarty registers its own autoload function, using the spl_autoload_register() function. Having my own __autoload() function breaks this, unless I register my own function with spl_autoload_register() as well. So the solution looks like this:

function autoload() {
  // my old stuff, but no more loading of Smarty libraries
}

spl_autoload_register("autoload");

Very simple solution, if you just get the right hint. So maybe if somebody stumbles upon the same error message, this may be of help to resolve this nicely and quickly.

If you are interested in seeing my post in the Smarty forum, it can be found at http://www.smarty.net/forums/viewtopic.php?p=65975.

How to detect the user’s preferred language – smarter than Google

Sometimes I find Google annoying. Don’t get me wrong, I am not one of the many Google haters out there. They have done amazing things and especially since they have released WebM as Open Source and royalty free video format, they have earned a bonus in my attitude towards them. And even though Google Chrome is not my personal favorite, I have to admit that Chrome has brought a great momentum into the development of web browsers (and therefor the WWW as a whole) which users of any browser benefit from. Last but not least, I use a lot of Google’s services and they do their job quite well. So all in all, Google’s record from my point of view is pretty good.

But one thing really sucks. I use an English operating system. I use an English Firefox (locale en-US). All the language preferences in the Google profiles of my accounts are set to English. Nevertheless, I often get pages from Google delivered in German by default. How they do that is quite obvious, or lets say, there is only one explanation how they may do this: they identify my home country based on my IP address. There are services that provide the data and they are easy to implement, sometimes even for free, like MaxMind‘s GeoLite Country database. Also I am using these services and I believe there is nothing wrong in doing so, except for a few things – and one of them is to identify the assumed web page visitor’s language preferences based on his or her home country.

Thankfully, I am only a lightweight victim of this practice, because I speak the language which I get served based on their guesses. But how happy would a Japanese tourist on vacation in Austria be to get his pages delivered in German, only because he uses an Austrian IP address? There are many reasons why a person located in one country may not understand the language that is spoken there. I only have to drive about 20 kilometers to get into such a country (the Czech Republic). So to assume that a person’s preferred language is the language spoken by the majority of a country (what about minorities or countries that have more than one language?) is very wrong.

What are better solutions? As I mentioned, I use an English operating system and an English browser. Almost every browser sends a user agent string. My currently most frequently sent user agent string for example is “Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7”. Every web server that receives a request from a user agent (usually a browser) can read this user agent string and process it accordingly.

What can we read in mine, amongst other information? en-US. So the locale tells a web server that it’s a browser (a Firefox 3.6.7) in American English. Now guess what my preferred language will be? Is it likely that I use a browser in a language which I don’t want? Is it likely that a tourist in a different country uses a browser in a language that he or she doesn’t want? It’s certainly possible (like if there is a terminal in the hotel room or an Internet Café), but nowadays most people have their laptops, notebooks, smart phones etc. And their browser language is still their preferred one, regardless where they are currently located. So the browser language serves as a much better criterion to assume a web site visitor’s preferred language.

Alright, no big rocket science so far, and to be honest, there is no big rocket science to come. At one point, when I was annoyed about Google’s failure to identify correctly which language to deliver me, I wondered, how hard would it be to implement the (in my humble opinion) better solution, using the web browser’s locale. The answer is far from being rocket science. The solution can be as easy as this:

First, get yourself a recent copy of the Zend Framework and install it so you make its libraries accessible to your code. You can add an __autoload() function, something like this:

function __autoload($classname) {
    if (substr($classname, 0, 4) == "Zend") {
        $classname = str_replace("_", "/", $classname);
        require_once $classname . '.php';
    }
}

or even easier, use the Zend Framework AutoLoader:

require_once 'Zend/Loader/Autoloader.php';

Zend_Loader_Autoloader::getInstance();

Everything we need to identify the browser language and locale can be found inside Zend_Locale.

The constructor of the Zend_Locale class allows to set the desired language or locale. In addition to that, there are three predefined constants named Zend_Locale::BROWSER, Zend_Locale::ENVIRONMENT and Zend_Locale::FRAMEWORK. According to the Zend_Locale introduction manual page they do the following:

Zend_Locale::FRAMEWORK – “When Zend Framework has a standardized way of specifying component defaults (planned, but not yet available), then using this constant during instantiation will give preference to choosing a locale based on these defaults. If no matching locale can be found, then preference is given to ENVIRONMENT and lastly BROWSER.”

Zend_Locale::ENVIRONMENT – “PHP publishes the host server’s locale via the PHP internal function setlocale(). If no matching locale can be found, then preference is given to FRAMEWORK and lastly BROWSER.”

Zend_Locale::BROWSER – “The user’s Web browser provides information with each request, which is published by PHP in the global variable HTTP_ACCEPT_LANGUAGE. if no matching locale can be found, then preference is given to ENVIRONMENT and lastly FRAMEWORK.”

And this is what we want!

Lets get to the code:

$zend_locale = new Zend_Locale(Zend_Locale::BROWSER);

// returns en for English, de for German etc.
$browser_language = $zend_locale->getLanguage();

// returns en-US for American English, en-GB for British English etc.
$browser_locale = $zend_locale->toString();

Three lines of code to get all the information we need. And how to make a choice which language to serve based on that? Lets assume we have a site in English, French and German. French browsers should get French, German browsers should get German and everybody else should get English:

$site_language = "en";
switch ($browser_language) {
    case "de" :
        $site_language = "de";
        break;
    case "fr" :
        $site_language = "fr";
}

And that’s it. That’s all Google would have to do to make me happy. I assume, their IP address based identification code requires more lines, and is still a poorer solution in my opinion. There are additional benefits to this solution. Want to display date and time according to the locale? Here is what to do:

$zend_date = Zend_Date::now();

$date_time = $zend_date->get(Zend_Date::DATETIME_FULL, $zend_locale);

print $date_time;

My default browser now shows me “Friday, July 23, 2010 2:14:58 AM Europe/Vienna”. If I fire up a German browser, the same page delivers me “Freitag, 23. Juli 2010 02:17:11 Europe/Vienna” and there may be answers like “vendredi 23 juillet 2010 02:17:56 Europe/Vienna” (French), “viernes 23 de julio de 2010 02:18:29 Europe/Vienna” (Spanish), “pátek, 23. července 2010 02:18:53 Europe/Vienna” (Czech) or “2010年7月23日金曜日2時19分17秒 Europe/Vienna” (Japanese) as well. It’s pretty cool how the Zend Framework can make such tasks very simple ;).

Where is a solution like mine being used in the wild? I don’t know where as of the time of this writing, but I know where very soon. The MySQL website will soon launch new localized content, delivered to people who we think really want to see these languages. We try very hard not to annoy people by enforcing a language upon them which they would not like to choose.

And remember: to make good guesses is good. The best solution however is to provide choice! If you make assumptions and even if the assumptions are well-founded, always leave people the choice to select what they want. There may be situations which you are not thinking of and because of some unusual circumstances, somebody may still want to choose differently than you would think.