Compiling ZoneMinder with libjpeg-turbo and JPEG_LIB_VERSION error

If you’ve ever tried to build ZoneMinder from source and been frustrated by the following compile error, then I hope this helps you.

[ 30%] Building CXX object src/CMakeFiles/zm.dir/zm_image.cpp.o
 /u1/src/ZoneMinder/src/zm_image.cpp: In member function ‘bool Image::ReadRaw(const char*)’:
 /u1/src/ZoneMinder/src/zm_image.cpp:616:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
 /u1/src/ZoneMinder/src/zm_image.cpp: In member function ‘bool Image::ReadJpeg(const char*, unsigned int, unsigned int)’:
 /u1/src/ZoneMinder/src/zm_image.cpp:664:5: error: ‘JPEG_LIB_VERSION’ was not declared in this scope
 /u1/src/ZoneMinder/src/zm_image.cpp: In member function ‘bool Image::WriteJpeg(const char*, int, timeval) const’:
 /u1/src/ZoneMinder/src/zm_image.cpp:825:5: error: ‘JPEG_LIB_VERSION’ was not declared in this scope
 /u1/src/ZoneMinder/src/zm_image.cpp: In member function ‘bool Image::DecodeJpeg(const JOCTET*, int, unsigned int, unsigned int)’:
 /u1/src/ZoneMinder/src/zm_image.cpp:956:5: error: ‘JPEG_LIB_VERSION’ was not declared in this scope
 /u1/src/ZoneMinder/src/zm_image.cpp: In member function ‘bool Image::EncodeJpeg(JOCTET*, int*, int) const’:
 /u1/src/ZoneMinder/src/zm_image.cpp:1090:5: error: ‘JPEG_LIB_VERSION’ was not declared in this scope
 make[2]: *** [src/CMakeFiles/zm.dir/zm_image.cpp.o] Error 1
 make[1]: *** [src/CMakeFiles/zm.dir/all] Error 2
 make: *** [all] Error 2

jpeglib-turbo/include/jconfig.h (from your installed jpeglib-turbo-dev) has:


And to avoid including this more than once the wrapper libjpeg-turbo/include/jpeglib.h has:

#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */
#include "jconfig.h" /* widely used configuration options */

So far so good… The problem comes when zoneminder wants to compile zm_image.cpp

the include path is:

 -> zm_image.h
   -> zm_jpeg.h
     -> jinclude.h
       -> jconfig.h   (from jpeglib-turbo)
     -> jpeglib.h     (from jpeglib-turbo)

Now, this *should* all work properly! I suspect it has something to do with cmake and scope and by the time we get back to jinclude.h it no longer has the define.

My fix was to take the version from my jpeglib-turbo/include/jconfig.h and simply add it to zoneminder’s jinclude.h:

#include "jconfig.h" /* auto configuration options */
#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */


Add the 3 blue lines after the jconfig.h include. Once done, compile should complete properly.

Hope this helps other get past this hurdle.



TomTom GO launched


On March 25, 2015, TomTom announced that it was replacing all (android) TomTom applications with a single app called TomTom GO Mobile. The main “problem” with previous TomTom applications were that there was a separate app for each region, or maps, and you purchased them all separately.

TomTom GO Mobile creates a single central app that can download any map worldwide. And it comes with free lifetime maps. It provides the first 50 miles free each month and heavier users can take out a subscription for unlimited driving.

This is good right? Sounds good on paper, but there is a catch. A huge catch, and one anyone who paid for previous versions of the software are now becoming all too painfully aware.

The feature list of the new app contains:

– Lifetime World Maps: Always drive with the latest maps for over 100 countries**

** You can download 4 or more full updates every year for the life of your app.

TomTom reserves its right to unilaterally withdraw and/or to amend this offer and/or to amend the terms and conditions.

So basically, TomTom can, and will, stick it to you when they feel like it. Read on for how this launch is doing exactly this to, at least, all existing Android customers.

18 months ago I bought TomTom U.S. & Canada for $40 because I frequently visit the states and that’s the only place I really need navigation assistance. At time of writing the feature list for the app still contains the promise:

›› FREE Lifetime Maps. Download 4 or more full updates every year for the life of your app.

Also note that there are no ** caveats to that.

I took TomTom at their word. I believed them. Yes, I’m a dumbass and got suckered.

So TomTom has a web page that isn’t linked to from their app page, that defines “life of your app”: (emphasis, mine)

What are Lifetime Maps?

Updated: 19/11/2014 03.36 PM

If you buy a navigation device or smartphone app which includes Lifetime Maps, you can download 4 or more full updates of your map every year for the lifetime* of your product.

Lifetime Maps are available without additional charge and for as long as the product is supported.

The map updates are the full updates for the map that is pre-installed on your device or that is installed on your smartphone app. The geographical coverage and feature support in the map will continue to match the original version, as long as the original is commercially available.

You will receive all available updates to road network, addresses and Points of Interest in these releases.

*Lifetime – this is the useful life of the device, which means the period of time that TomTom continues to support your device with software updates, services, content or accessories. A device will have reached the end of its life when none of these are available any more. The useful life of the smartphone app means the period of time that TomTom continues to support the app with updates. 

So, to cut a long story short, all TomTom has to do is replace the app you paid good money for with a different app and your “lifetime” maps disappear.

TomTom has announced that existing TomTom apps will get map updates until October 2015, after which they will cease.

So in total, my $40 bought me 2 years and 2 months of TomTom. Not exactly a “lifetime” by any standard.

TomTom’s attempt to appease customers is to offer a 3 year subscription upgrade for 50p, instead of the usual £34.99 – so in 3 years time I can expect to pay at least £34.99 ($50) every 3 years for updates.

Nice scam TomTom.  If this isn’t a “bait and switch” I don’t know what is.

A disappointed customer.


On Software and Game Copyright and Second Hand sales.


This morning I got into a little twitter spat with a local game developer Matt Johnston. Basically he is arguing against companies like GameStop because they do not provide any revenue back to the original developers of the game. As he is a game developer, he is very obviously on the side of the games companies.

Matt made a blog article and very nicely quoted me in the article – one of the tweets during the to-and-fro conversation. Well as much as 140 characters allows.

Matt makes several points, one of which is that if we allow* a second hand market, then DRM will happen; and we don’t want DRM, so we shouldn’t have a second hand market.

(* note that it is not the right of the games companies to allow or ban it in the first place).

DRM is a red herring and not at the heart of the issue. DRM may be the games companies answer to the problem it perceives – but at the end of the day, DRM only hurts those people who actually pay for the game.

I could go onto many underground sites and find the latest games “for free”. Who wins there?

I don’t as I do believe the game should be paid for. I have a large collection of both Wii originals, and a large Steam archive.

Having said that, morally, I have a real objection to the games companies thinking they can ride roughshod over consumer rights and long established principles and doctrine of first sale.

The second hand market is both legal in the physical works *and* in the digital world. And thankfully we now have case law to back this up.

Last month, in the EU, Oracle lost a case (Oracle vs UsedSoft) trying to prevent resale of licenses to its software.

The court wrote:
“A rightholder who has marketed a copy in the territory of a Member State of the EU thus loses the right to rely on his monopoly of exploitation in order to oppose the resale of that copy.”

Further, Oracle, and Matt here, opposes further distribution based on licensing terms. The court also rejected this view, thus:
‘The principle of exhaustion of the distribution right applies not only where the copyright holder markets copies of his software on a material medium (CD-ROM or DVD) but also where he distributes them by means of downloads from his website. Where the copyright holder makes available to his customer a copy – tangible or intangible – and at the same time concludes, in return form payment of a fee, a licence agreement granting the customer the right to use that copy for an unlimited period, that rightholder sells the copy to the customer and thus exhausts his exclusive distribution right. Such a transaction involves a transfer of the right of ownership of the copy.
‘Therefore, even if the licence agreement prohibits a further transfer, the rightholder can no longer oppose the resale of that copy.’

In summary, as a gaming company, you would love to make income on the second hand sales of your games, who wouldn’t.  However, morally it is wrong.

Would you like the government to charge VAT on second hand goods? No? – they already got their cut, as have you in your first sale.

Thankfully, the law agrees with me.



Experts Exchange, Google, and misappropriation of copyright.

Opinion Piece

I was googling (as a verb) and came across a rather peculiar message at the bottom of Google’s search results:

In response to a complaint we received under the US Digital Millennium Copyright Act, we have removed 1 result(s) from this page. If you wish, you may read the DMCA complaint that caused the removal(s) at

Interesting – never saw that before!

Following the link to Chilling Effects shows a copy of the complaint which has some interesting text in it.

Experts-Exchange makes a detailed itemisation of their registered Copyrights, none of which I find objectionable, however, the complaint then goes on to list several issues against the Defendant, the first and most egregious of which is:

a direct “copy and paste job” lifting the content of Plaintiff’s question and answer forums and inserting them onto AllFAQ’s website. AllFAQ’s question and “Solutions” are verbatim to Experts-Exchange’s questions and “Accepted Solutions;”

From this Experts Exchange is accusing of Copyright infringement against Experts Exchange owned Copyright.

At first glance, this might seem fully justified – but look at what they are claiming copyright on.  Experts Exchange are assuming copyright ownership of content that you, and I, and all their users create by asking and answering questions on their web site.

I looked at Experts Exchange’s Terms of Use and could not find any agreement that users were assigning their rights and copyrights to Experts Exchange. The relevant paragraph is:

“5. Content License

EXPERTS EXCHANGE enables Members to post problems or questions,
proposed solutions or answers, information, comments and other content
(“Your Content”) to its Site. When you post Your Content to the Site,
you understand and agree that Your Content can be viewed and used by
other Members who visit the Site with or without attribution.

You represent and warrant that you own or otherwise control all of the
rights to Your Content and that use of Your Content by EXPERTS
EXCHANGE and its affiliates will not infringe upon or violate the
rights of any third party. Before you use EXPERTS EXCHANGE Services to
post any information or content that is protected by intellectual
property laws, you shall have acquired the legal right to do so from
the owner or authorized licensee of such information or content.

By registering with EXPERTS EXCHANGE and posting Your Content on the
Site, you hereby: (i) grant EXPERTS EXCHANGE a non-exclusive,
perpetual, irrevocable, unrestricted, transferable, fully
sub-licensable, worldwide, royalty-free license to use, distribute,
display, reproduce, perform, modify, adapt, publish, translate and
create derivative works from Your Content in any form, media or
technology, whether now-known or hereafter developed; (ii) grant
EXPERTS EXCHANGE and its affiliates and sub-licensees the right to use
the Member Name that you submit with Your Content for purposes of
attribution; (iii) authorize EXPERTS EXCHANGE to assert and prosecute
claims against any third-party making any unauthorized use of Your
Content, including any use that violates this User Agreement
(“Third-Party Claims”); and (iv) appoint EXPERTS EXCHANGE as your
attorney-in-fact for the purpose of asserting and prosecuting
Third-Party Claims. If you do not wish to have Your Content attributed
to you, then you must notify EXPERTS EXCHANGE at

Experts Exchange acknowledges that the copyright belongs to the author as “Your Content” and that by posting you are granting them extensive licenses to use that content. You are not assigning your copyright to Experts Exchange.

Now I am glad that their ToU does not attempt to wrest copyright ownership from its rightful owner, that is right and proper. is demonstrably guilty of screen-scraping the Experts
Exchange web site and I do not condone those actions at all. However, looking at what
they copied – it was the Title, Question and Accepted Solution text –
the copyright of 100% of that is with the original authors, and not
Experts Exchange.

Thus, in my opinion, this complaint against is without merit and should be dismissed.

It would also appear that Experts Exchange has also abused the provisions of the DMCA in forcing Google to remove the content. Google should restore the links.

And finally, Experts Exchange should implement some technical measures to prevent automated scraping. Find better ways to improve your search ranking, and if your competition beats you don’t ask your own members how to do better SEO; be told by them that you have no Copyright Claims on the content; and then proceed to file DMCA take down notices when you know you have no (copy)right.

The O2 Joggler – A first hack.


If you were not aware – O2 last week reduced the price of the O2 Joggler from £149.99 to £99.99 to £49.99.  Nothing remarkable in price reductions, however what is remarkable is what you actually get for your money.

The O2 Joggler is a silent 7″ touchscreen device with Intel Atom Z520 running at 1.3Ghz, 512Mb ram, 1GB internal flash storage with additional storage available via an external USB port. What makes the device really exciting is that it also has a 1GB ethernet (Realtec 8168) and Wifi.

Looking at that – I know you’re all thinking “linux box” – but conveniently, the default operating system on it is based on Ubuntu 8.04 and busybox, The frontend is a custom flash driven UI developed by OpenPeak (makers of the Jogger which is rebadged by O2).

There are plenty of clever individuals over at in the #mer channel on freenode who are working to allow the Joggler to run other Operating Systems such as Android, Ubuntu Netbook Edition, MID, even Windows and OSX.

However, the standard OS supplied is also pretty powerful and allows significant customisation.  You can enable telnet just by turning it on with a custom USB stick plugged in. To do some of the things I’ll be describing here you will need to have started with that.

Once you can telnet in, the world opens up and you can do lots of things that you would expect* to be able to do in a linux system. (* except run a web browser…. at this time – we don’t have web access
with the stock OS due to the custom flash GUI interface.

Lets install some useful utilities, how about perl, terminfo, irc clients, bit torrent, rsync, ssh/scp ?   Yes, I know what you’re thinking – overnight silent downloads – no need to leave PC on… nice…

I’ve built several of these utilities with installation instructions and uploaded them over here:

Feel free to download, examine, install etc.  Read the README on the download page – it explains how to do it. Most of the packs include an script that will provide an installation safety net – it won’t overwrite existing files or libraries.

Usual disclaimers apply – you try these applications at your own risk. I accept no responsibility if you manage to brick, fry or otherwise trash your joggler.

Comments, suggestions for other applications are always welcome.

Update: Thanks to NP – seems I was a little too brutal with the library stripping to keep the download sizes small and I missed some required libraries (that I mistakenly thought were in the standard Joggler distro).   I have rebuilt the following packages as they were missing some libs: rtorrent, rsync, sudo,ssh
The screen package has been rebuilt too to add one final tweak (to the installer script) so it can be used by non-root users – the only difference you need to do is run the command: chmod 666 /dev/ptmp /dev/tty

Is BT still collecting usage data?

After the recent scandal over BT using Phorm (see here and here) is it still possible that BT is still covertly collecting data profiling its user’s internet usage?

I have, as part of my home BT Total Broadband package, a HUAWEI Mobile Connect 3G Modem.  This is a USB dongle that provides internet service.   I rarely use it, but because of the storms last night my internet connection has been very unstable, therefore I plugged it in today.

When I started the “BT Connection Manager” software, it informed me that there was an update to the service and would I like to download it? Yes, ok, and a couple of minutes later it began to install itself.  Then popped up the obligatory EULA which contained the paragraphs:

Installation of this Software will automatically apply a unique identifier to the Software, this identifying feature will only be used in accordance with the BT privacy policy which can be found at

This software automatically collects session and client parameter Information for all connections made via this Software. This information is automatically transmitted to BT at the start of each session where Internet access is available. This session information will only be used in accordance with the BT privacy policy which can be found at”


I also note that the software package uses the Open Source packages libCurl, openssl and sqlite.  Combined they enable the package to record “session and client parameter Information for all connections” in the database (sqlite) and to encrypt (openssl) and transmit the data via a web request (libcurl) back to BT.

At this point I am unable to confirm if such a transmission is taking place as I declined the EULA, but would welcome feedback or comments from others that are able to investigate this more fully.

Update: Even though I clicked “Cancel” to reject the EULA – it did update the application and actually started it up before I exited the installer.  Guess I have this privacy invading feature now.

Borland, Farewell my sweet.

Today, May 6 2009, marks the day that Borland, that once great master of all software development has finally recognised there was no other recourse but to up and sell itself off in order to survive.

Back when I was a teenager, in the early 80s and personal computing was coming to the fore – I, and many others, aspired to work for that great company Borland. It was the pinnacle of language development and development tools and we wanted to work there. However, based in Ireland it was never to be.

Also, once upon a time I happened to be working for a very promising young company with a fantastic product line called Segue Software, based in Boston, MA.  Segue also had its troubles but a new CEO saw its fortunes turn and it was climbing to success. This success was noticed by the aforementioned Borland as it tried to re-invent itself as an Application Lifecycle Management (ALM) company.  The same day it was announced that Borland was acquiring Segue, it also announced it was selling its developer tools division (that’s Delphi, JBuilder, and later Delphi for PHP, 3rd Rail line of products).

This was such a bitter-sweet time for many.  I was overjoyed that I was going to work for Borland (childhood dream) – it didn’t matter I wasn’t going to work with the developer tools, working for “Borland” would just be cool.  Sadness also because our little 200-man company was being consumed by a 1200-man behemoth (relatively) and no-matter which way you looked at it, people were going to lose their jobs.  Pretty much the entire US East Coast staff (Segue Head Office) lost their jobs and the office was closed.  Product development labs and Technical Support survived, simply by virtue that it was the product and product skills that were purchased, not the G&A functions – they could go.

I ‘lived the dream’ for the next 2.5 years in the IT department. Despite being remote, I loved working with the rest of the Borland teams as I was intimately involved in the merging/migration of Segue’s systems into Borland’s. I also had the pleasure of working with several departments to architect and deploy several new platforms (such as product downloads and licensing via Intraware, and the companies, SFDC, deployment).  I’ll treasure the time I spent at Borland.

Of course there were several WTF moments. Most significantly, for me, was the company “hanging its hat” on BMS (Business Management Solutions) which ultimately proved to be a hatstand made of jello. Very few, outside of management and that product team, believed in it.  Another significant WTF for Borland was, If you plan to be the Application LIFECYCLE Management company – why divest yourself (for a paltry $27m) of two of the world’s major AppDev toolsets (Delphi and JBuilder). You’ve just removed the feeder market and upsell opportunity into your ALM business. Finally, and internal WTF to get off my chest, on what planet does the IT department belong as a subdivision of the HR department?

Borland will live on in the hearts of many of us who knew what she used to be. I think I left Borland a better place than I found it (as long as you don’t look at the stock price ;), and I made some good friends. At the end of the day, there isn’t much more you can ask from your tenure.
It is sad that today if you ask a typical Software Engineer if they know who Borland is, they’ll respond “Who?” which typifies the company’s slide into obscurity.

I wish the best of luck to my former colleagues, who I’m sure, will be wondering what is to happen next. I also hope that the new owners, Micro Focus International (who?), have good fortune with their ALM drive. Perhaps the Borland name might live on as a brand for a suite of ALM products – who knows what they’ll do.

In the immortal words of Dr. Seuss “Don’t cry because it’s over. Smile because it happened.”

PHP algorithms: Determining if an IP is within a specific range.

I spend a lot of time lurking in the #PHP channel (efnet and freenode, please – no flamewars) and this topic is a commonly asked one that usually gets a simplified answer in the form of using strpos(), or at best an ip2long() in a greater than and less than answer.

Unfortunately although people usually understand that an IP address is simply an unsigned 32 bit integer, and is easily determined, usually with $_SERVER[‘REMOTE_ADDR’], where the real challenge is – is in specifying the range within which they wish to check that IP address.  IP ranges are usually specified in three common ways (in increasing complexity):

  1. Wildcard: 192.168.10.*
  2. Start-End range:
  3. CIDR*:

* Classless Inter-Domain Routing

The Wildcard method, or “classy”, allows you to work at Class A (10.*.*.*), Class B (172.16.*.*) or Class C (192.168.10.*) levels of granularity which is how we used to do things in the old days (before the Web decided to make the Internet popular).  But, increasingly, this just isn’t granular enough for practical purposes.

Thus was born CIDR (yes, I’m skipping talking about Start-End ranges for now).  CIDR brought about the concept that we really didn’t need to break networks on 8, 16, 24 bit boundaries and we could be more granular by allowing the use of any number (from 2-30) to specify a range of networks.  Details on why you can’t use “31” is beyond the scope of this article.

CIDR renamed the former Class A, B and C networks as /8, /16 and /24 respectively and reflects the left-most significant bits of the 32-bit IP address.  Thus was born the ability to specify very specific IP ranges in the form a.b.c.d/xx.   However, part of the problem with this is that although it concisely describes the network start and end, most normal mortal humans couldn’t decipher it. CIDR addressing can also be specified in the form of a longer netmask, e.g. a.b.c.d/

Thus, the simplified form of Start IP – End IP was put in place for mere mortals and is typically used by those without a networking background.  It also features heavily in consumer broadband routers and notably in Microsoft Windows DHCP server.

So having explained how a range, and by inference, that a netmask is, how can we use this knowledge to help us in determining if an IP is within a range?

What this article will attempt to do is guide you though the construction of algorithms to make the checking of IPs simpler.

Logically, Method 1 (the Wildcard), can be easily converted to Method 2 (Start-End range) by using setting Start and End to the Wildcard string and replacing the “*” character with 0 for the Start and 255 for the End, thus for example, “192.168.10.*” becomes “” which should (I hope) be obvious to everyone.

We can then proceed to evaluate both Method1 and Method2 in the same way.  In this we’re simply going to use the PHP built in function ip2long() on all 3 values and perform a mathematical check for Start <= IP <= End.

list($lower$upper) = explode('-'$range2);
$lower_dec ip2long($lower);
$upper_dec ip2long($upper);
$ip_dec ip2long($ip);
return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );

We have, however, a complicating factor here – PHP does not do unsigned integers (32 bit) – which would be necessary for this math to work properly.  We can negate this by switing to floating point data types.  PHP stores  floating types as 64 bit and so will have no problem with IPv4 address space (note – this obviously isn’t granular enough for 128bit IPv6 addressing). Therefore the simplest way to solve the Start <= IP <= End problem with IPs and floating point numers is the following piece of code:

$lower_dec = (float)sprintf("%u",ip2long($lower));
$upper_dec = (float)sprintf("%u",ip2long($upper));
$ip_dec = (float)sprintf("%u",ip2long($ip));
return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );

Next we have the challenge of handing the CIDR netmasks. What we could do is to take a CIDR format IPaddress/netmask and calculate the Start and End IPs of that block and proceed as before – but that would be no fun – and would mean I haven’t really taught anything through this article.

The method we’re going to use here is how all the world’s Internet routers determine if a destination IP is in a specific CIDR address space. And we’re going to get down and dirty with bitmasks and logical bitwise operators.

So using a real world example, my webserver IP and the netblock within which it resides is, how does this all work?

Well the /27 indicates that the first 27 bits of the IP address are the same network and IP address in that network (range) will have those same identical first 27 bits.  Bits 28-32 are variable and allow 5 bits of variation.  If you know your binary, then this means 32 possible IPs. (However with routing, you can’t use the bottom and top IP from any range as these are special and mean the network and broadcast addresses respectively. [This is also why a /31 isn’t much use (except for PPP links) as you can’t use the 2 addresses that space gives you]).

So thinking logically, bitwise, if I take my IP address and the CIDR spec, then all I have to do is check that the first 27 bits all match and I’m good. Correct.  So how would we do this in PHP? Sound’s simple, lets just use PHP’s bitwise logical AND operator: &

Again, correct.

In order to do this we need to convert 27 into what 27 really means – a 32 bit number of 27 ones and 5 zeros in binary (which is what really looks like).

In pseudo-code you could then do if (IP & BITMASK) == (RANGE & BITMASK) then all is good and you know that the IP is within the range.

Visualising this using our real IP address (using the very handy unix tool ipcalc):

Address: 01010000.01001100.11001001.00100101
Netmask: 11111111.11111111.11111111.11100000
Wildcard:        00000000.00000000.00000000.00011111
Network: 01010000.01001100.11001001.00100000
HostMin:    01010000.01001100.11001001.00100001
HostMax:    01010000.01001100.11001001.00111110
Broadcast:    01010000.01001100.11001001.00111111
Hosts/Net: 30

You can see this in the Wildcard line of, and the Network ORed with Wildcard results in the Broadcast address:

Knowing this, then the IP address ANDed with the Network address will result in the same value as the Range ANDed with the Network address and so can be used as a comparison for an IP residing within that broadcast range.

How can we work out this Network address in PHP, again we have two strategies, one is to so a simple substr() and take the left most significant bits of the range and then simply pad out to the right with 0s.  Or we can do some math with “NOT of 2 to the power of (32-range) – 1”. Thus for our value /27 this gives us the decimal value 31, NOTed results in (65536-31)  (representational in the bit form – PHP will see it as a negative integer, but we don’t need to worry about that).

I’m sure by now, your screaming for some code (and if you stuck around this long, you really deserve it).

Code to manipulate a range/netmask into a broadcast address, using math, assuming:

$ip "";
$range "";
$netmask 27;

We can convert the IPs to long integers using ip2long (denoted by variable_dec – dec being short for decimal):

$range_dec ip2long($range);
$ip_dec ip2long($ip);

This gives us the basis of our math, we now just need to work out the broadcast address.

Strategy 1 using str_pad to create a string by padding with 1s and 0s.

$netmask_dec = bindec( str_pad('', $netmask'1')
                     . str_pad(''32-$netmask'0') );

We can achieve the same result though mathematics by NOTing the wildcard value. This is our Strategy 2:

$wildcard_dec pow(2, (32-$netmask)) - 1;
$netmask_dec = ~ $wildcard_dec;

Once we know the netmask address (in decimal) as we have here, we can know that, if by ANDing this with the original IP to check results against the Range ANDed with the Netmask, then the IP is within the range defined by the range/mask.

This can be checked easily with:

return (($ip_dec $netmask_dec) == ($range_dec $netmask_dec));


I have pulled all of this logic together in a easily included file to provide a single function called ip_in_range($ip, $range) in which $ip is the IP address you want to validate and $range is a any of the above formats, Wildcard, Start-End addressing or CIDR.  The function will return a simple TRUE or FALSE if the IP is in that range.

The source code to the all-in function is available here:

With an example run (and source code):

I hope this article has been educational, please feel free to leave comments or feedback.
Update: There have been questions about PHP’s signed integers and my use of bit operations in the code.   It is important to recognise that when dealing with signed or unsigned 32 bit integers purely as bit patterns for masking with a netmask or broadcast address pattern – the fact that a number ( or above) really is negative, doesn’t have any impact on the validity of the result.  The only impact to not having signed 32 bit integers is in the Start-End range check (example 2 above: where a range spanning the switch from positive to negative would be catastrophic to the check.  We can safely work around that problem by using floating point numbers as we are only doing <= and >= comparisons and not attempting any bitwise operators (which don’t work on floats).