51Degrees
-
Been away for a while but I had to post this thing.
51Degrees.mobi provides a mobile detection library.
Minor WTFs:
- the semi-OO library works by auto-executing functions loaded in nested, dynamically included files
- Some of the functions use reference arguments and also return stuff, but not all the time
- some includes are done with include(), not include_once(), which makes the previous two items in this list even more optimal
- the library uses session variables directly
- The PHP SDK is not Composer friendly and has its own autoloader approach
The core of the product is the data file, which contains interesting information for each device such as screen width, mobile or not, svg or not, etc. There is a free data file but monthly updates require a membership ($360/year). This is what the data file content looks like:
12496 IsMobile|0|True ScreenPixelsHeight|0|800 ScreenPixelsWidth|0|400
18092
3508
AnimationTiming|0|False
BlobBuilder|0|False
Canvas|0|True
CssBackground|0|True
Prompts|0|True
Selector|0|True
Svg|0|False
TouchEvents|0|False
WebWorkers|0|False
Xhr2|0|False5096
3441
AnimationTiming|0|False
BlobBuilder|0|True
Canvas|0|True
CssCanvas|0|False[total about 100k lines]
The numerical identifiers ARE NOT lookup keys. They are actually part of the data. From what I understand in the code, here is how the data is loaded:
- A basic regex is performed on various parts of the user agent string; this returns a "handler" ID*
- A php file matching the handler ID is included dynamically (there are about 130 of those)
- The code in the handler file is executed and returns an array that contains a bunch of numbers.
- The numbers in the array are offsets passed to fseek to locate the desired chunk of data in the data file
- The result is pushed in the session but also in a local array that is expected to be used in the parent scope after including the library
*In addition to the regex, the matcher calculates the levenshtein distance of some pieces of the sub-elements in the user agent string, but I could not say if this is a WTF as I have no idea why they do this. The /*TODO*/ comments above each function unfortunately does not help to understand this.
I have no idea how someone came up with this design, but this is quite interesting to debug.
-
I've just stared at that list for the past few minutes, trying to get into the mindset of the person who designed it so I can understand their logic. So far I've failed. Possibly because I'm drunk, but then looking at that list, I'd have thought being drunk was a prerequisite.