Posts filed under ‘PHP’

Making administrative web apps in PHP

What do I mean by administrative web apps?  Basically, a web app that lets you update a series of database tables,

Let’s take my most recent one as an example.  We are about to deploy LTE capable routers (Referred to as Modems in some places in this blog entry) to our remote locations.  800+ of them.  Each remote site will have an LTE router with modem and two SIM cards.  One of those SIMs will be active and the other will be there so we could switch to it, in the event we have trouble with the primary SIM (Vendor A has trouble, Vendor B might work better).  Each Vendor requires certain data when activating a SIM.  One wants the modem IMEI, another wants the modem MEID.  They all want to know which SIM ID is involved.  Oh, and each SIM is associated with a static private IP address.

The easiest way to manage such a thing is probably via a database table that can be edited via a web interface.  If it’s just you doing it all, perhaps you can edit the tables “in the raw” using something like PhpMyAdmin.  But, if you have a team involved, you might want to dial back the control a bit.  This is where you’d want to built a website to manage these database tables intelligently.

Rule #1:  Use a Web Framework!

A couple years back I learned about Bootstrap, the framework that lets you easily create clean, professional looking websites.  Using one of the frameworks will make your web apps look clean and professional.  Just pick one, and stick with it.

Rule #2:  Authenticate!

Whenever you are creating any sort of administration web app, make sure authentication plays a part.  You want to be sure that the people using your web apps are supposed to be using it.  While this is a “duh” statement for anyone writing publicly available apps, it also holds very true if it’s a private app that’s only visible to company employees.  In my case, I had a rudimentary system in place for a very important page, but many others were wide open.  While revamping the system using Bootstrap, I created a simple radius-based authorization include file to add to all the pages I wanted to secure.  I used a radius class I found online, I think this one.  I actually love it that I’m not very familiar with the class, as I’ve had to do so little with it.  I pretty much dropped it in, and it’s been working great ever since.  Since it’s just a single “include” line, securing other pages is drop-dead simple.

Rule #3:  Use Editor

This is an amazingly smart library of code.  With it, you can build a modern AJAX enabled web interface to manage your database tables very easily.  You may have to pick up a little bit of Javascript knowledge, but the back-end is PHP, and if you are half decent at PHP, you should be all set.

They have example code galore.  The majority of what you probably want to know how to do is right there.

If what you want to do isn’t listed in the examples, just ask!  Support on their forum is very good.  Most of my problems seem to stem from a lack of knowledge on the Javascript side of things.


Ok, time to talk about the elephant… No, Editor isn’t free.  It’s $119 if you are a solo developer, and goes up from there depending on the size of your team.  But trust me, it is so worth it.  If you were to try to write your own class library to do all the things Editor does, you’d spend many, many hours doing it, making the price tag a bargain.

Rule #4: Make an Audit Trail!

Any time you build a web interface that allows users to edit database tables for anything important, you should include code to audit the database tables, so you’ll see exactly who made what changes.  If you’ve used an authentication include, as I suggest, you can probably grab the logged-in user so you can write that into the audit trail as well.  I’m not suggesting this so you can beat up on the guy who made the mistake.  It’s so that you can quickly look back, see what has changed, so you can quickly fix the mistake.  It also allows you to do a little remedial training with whoever made the mistake, so they won’t make it again.

Now, an audit trail when using Editor is a bit of a challenge.  Unfortunately, the PHP code for Editor doesn’t include a smart audit capability or anything similar.  If you are serious about this, though, you can find the driver file for the database type you are using and modify it to create your audit trail.  Heck, a timestamped log file including the username and the UPDATE, DELETE, and CREATE SQL queries is probably all you need.  I actually parsed the SQL and wrote it out in an audit table so the NOC team can look through it (in another tab in the web interface) and figure out what happened, but that’s probably just me.

Rule #5:  Consider the Work Flow!

If you are writing this for someone else to use, it may be tempting to quickly write it in the fastest way you can, and then move on.  Don’t do it.  In my case, my users will be using this to keep 800+ sites straight.  That’s a big job, so I’m trying to make it as easy as possible.

Consider the things the users will need to do with the application.  When adding a new modem to my database, they’ll first scan in the IMEI (using a barcode scanner), then the MEID, so those are the first two fields on the “Create Modem” page.  The next item is the location number that will get this modem, then they can select two SIMs, and then a Vendor dropdown to indicate which SIM is active.  Design with the workflow in mind.

Build in logic to keep errors from happening.  In my case, I’m repopulating the SIM dropdown lists to only include SIMs that have not been selected before, since a SIM can only be in one modem at a time.  Similarly, if the user has selected AT&T and Verizon SIMs, don’t let them select Sprint as the Active Vendor.

Handle “special things” in the web app.  In my case, I’m going to have some LTE Survey kits that I’m giving “fake” location numbers.  I’ve added logic to the tool to prevent records marked with “fake” location numbers from being edited by the user.

July 4, 2015 at 6:40 pm Leave a comment

CradlePoint API info

Every CradlePoint router (with at least a reasonably recent firmware) includes a very nice API.

However, if you search looking for documentation on their website about it, you’ll only find information on the API for ECM, their central management service.

Here are a few very useful URLs that you can call with the Restful client of your choice:

Figure out what model of CradlePoint you’ve reached, and/or the serial number:
https://  [CradlePoint IP]/api/status/product_info/

“data”: {
“company_name”: “Cradlepoint, Inc.”,
“copyright”: “Cradlepoint, Inc. 2015”,
“mac0”: “REDACTED“,
“company_url”: “”,
“manufacturing”: {
“board_ID”: “050000”,
“mftr_date”: “20150401”,
“serial_num”: “REDACTED
“product_name”: “CBA850”
“success”: true

Get your firmware version (major.minor.patch):
https:// [CradlePoint IP]/api/status/fw_info
“data”: {
“build_date”: “Thu Feb 19 12: 00: 07 MST 2015”,
“manufacturing_upgrade”: false,
“major_version”: 5,
“custom_defaults”: false,
“minor_version”: 3,
“fw_update_available”: false,
“patch_version”: 4,
“upgrade_minor_version”: 0,
“build_version”: 13953,
“upgrade_major_version”: 0,
“upgrade_patch_version”: 0,
“build_type”: “RELEASE”
“success”: true

Find out if you’re connected:

https:// [CradlePoint IP]/api/status/wan/connection_state

“data”: “connected”,
“success”: true

Get your WAN interface IP:
https:// [CradlePoint IP]/api/status/wan/ipinfo
“data”: {
“netmask”: “”,
“dns”: [
“ip_address”: “”,
“primary”: “lte-REDACTED“,
“gateway”: “”
“success”: true

Too much good diag stuff to mention: 

Please note, I REDACTED most of the unique identifying info, but these fields are all available on your gear.  To get the portion of the URL that’s redacted, look in the “primary” key of the result of your WAN ip info, shown just above.

https:// [CradlePoint IP]/api/status/wan/devices/lte-REDACTED/diagnostics

“data”: {
“HM_PLMN”: “310410”,
“CELL_ID”: “176898562 (0xa8b4202)”,
“CS”: “UP”,
“PRD”: “MC400LPE (SIM1)”,
“VER_PKG”: “,005.010_002”,
“MDL”: “MC400LPE (SIM1)”,
“TXCHANNEL”: “20576”,
“MODEMOPMODE”: “Online”,
“ROAM”: “1”,
“VER”: “SWI9X15C_05.05.16.02 r21040 carmd-fwbuild1 2014/03/17 23:49:48”,
“CFGAPNMASK”: “65534”,
“MODEMPSSTATE”: “Attached”,
“RXCHANNEL”: “2576”,
“VER_PREF_PKG”: “,005.010_002”,
“RSRQ”: “-7”,
“RSRP”: “-90”,
“DBM”: “-69”,
“SCRAPN”: “16”,
“SS”: “100”,
“LAST_PIN”: “”,
“BANDULFRQ”: “824-849”,
“TX_LTE”: “-6.5”,
“RFBAND”: “Band 5”,
“SELAPN”: “1”,
“SINR”: “21.2”,
“EMMSTATE”: “Registered”,
“CHIPSET”: “9X15C”,
“MODEMTEMP”: “40”,
“HW_VER”: “1.0”,
“IS_LTE”: “true”,
“MFG_MDL”: “MC7354-CP”,
“MFG”: “CradlePoint Inc.”,
“PRLV”: “1”,
“LAST_PIN_VALID”: “False”,
“PRI_VER”: “05.03”,
“DEFAPN”: “1”,
“DORMANT”: “Dormant”,
“PUK_RETRIES”: “10”,
“EMMSUBSTATE”: “Normal Service”,
“MODEMIMSSTATE”: “No service”,
“CUR_PLMN”: “310410”,
“BANDDLFRQ”: “869-894”,
“RFCHANNEL”: “2576”,
“PRI_ID”: “9903437”
“success”: true

My favorite (so far) is a bit difficult to explain in this blog post, but I’ll try:

https:// [CradlePoint IP]/api/control/netperf

To use this, you need 5.4.0 or newer firmware, and you’ll really need your own NetPerf server, but if you get that set up, you should be able to initiate your own speed tests across the LTE link.  You’ll need to pass data to this one, though, so it’s a bit harder.  Here’s my data template, with words surrounded by percent signs as variables.

$json_template = ‘{“input”:{“options”:{“limit”:{“size”:%size%,”time”:%timeout%},”port”:””,”host”:”%host%”,”ifc_wan”:””,”recv”:%recv%,”send”:%send%,”tcp”:true,”udp”:false},”tests”:null},”run”:1}’;

After customizing this for the test that I want to perform, I do a HTTP PUT of this data.  In my case, with PHP, I have to pass my $json like this:  array(‘data’ => $json).

Anyhow, doing this kicks off a speedtest that runs for %timeout% seconds.  You can then to a GET to the /api/control/netperf URL and get a status, like so:

https:// [CradlePoint IP]/api/control/netperf

“data”: {
“input”: {
“tests”: null,
“options”: {
“udp”: false,
“limit”: {
“size”: 0,
“time”: 10
“tcp”: true,
“recv”: true,
“port”: null,
“send”: false
“output”: {
“results_path”: null,
“status”: “idle”,
“command”: null,
“error”: null,
“progress”: 0,
“guid”: -1
“success”: true

In the “output” section above, had I just performed a test, I could look at the value of “results_path”, which is a URL to the results of the test.

There is a TON of great info you can get from the CradlePoint API.  CradlePoint built their web interface off of the API, so pretty much anything you see in the web interface can be accessed via the API.  In fact, if you simply use a tool like HTTPwatch to look at the interaction between your web browser and the remote CradlePoint device, you’ll be able to learn how to do all this yourself.


June 30, 2015 at 8:29 pm 10 comments

Migrating an app from one database to another

We have a bunch of apps that run against a database, dating back about 10 years.  These apps have grown over the years.  The original database was done in MSSQL.  The apps that access this are mostly done in PHP.  We’ve recently needed to add a few fields to the database, but instead of trying to get them added to the MSSQL database, I took the approach of building a class to access the data.  This class actually reads some fields from the original MSSQL database, and others from a MySQL database.  The update logic is built into the class, so it doesn’t matter which database contains the field, it will perform the update to the appropriate DB.

So, this has all been working well now for the last 5 or 6 months, and now we want to take the next step.  We want to move all the fields that are still relevant to the MySQL database, and just stop using the MSSQL database altogether.  This is made more complicated by the fact that numerous apps access the MSSQL database directly.  In particular, there is one old VB.NET app that we want to eliminate.  I’ve already created a web page that does the majority of the things this old VB.NET app does, and it uses my new class.  There’s still a little work to do to get everything, but it’s close.

I’ve been trying to think of how to best handle the DB migration.  I see a couple of options:

1.  Duplicate the fields exactly (column name included) from the MSSQL DB into the MySQL DB, and have the class stop using the MSSQL DB.  This would require all the apps that access the MSSQL DB directly to be switched to MySQL.  That’s a lot of work, and will likely take a few days, perhaps even a week or so (especially given this time of year and the vacation days people take).  During that coding time, some apps are using the records from MySQL and others are using the MSSQL DB.  Since these apps manage the configuration of hundreds of routers and thousands of switches in about 700 remote sites, we really don’t want anything going wrong, as it could be a major pain to fix.

2. Create new fields in the MySQL DB to match the required fields from the MSSQL DB, but name them differently.  This gives us the ability to search easily through source code that accesses various field names (the MSSQL versions) to make the MySQL changeover.  This would be nice, but I believe this would also require us to code the class so that the class would synchronize the “duplicate” field in the MySQL DB with the appropriate field in the MSSQL DB.  If a record is updated using the MySQL field name, it would need to also update the corresponding MSSQL field with the same value.  Similarly, if the update used the MSSQL field name, it would need to update the MySQL field.  Finally, upon each load of data into the class, we’d need the class to compare the  corresponding fields, and if the values weren’t equal, make a decision on which one “wins”, and is then copied into the “loser” field.  The start with, we’d probably want the MSSQL side to win.  When we are certain we were done with all the code changes across a few servers, then it would be time to drop out the MSSQL code altogether.

I’ll probably give this a good bit more thought, and look through the source code a while before I come to a 100% answer, but I’m leaning toward option #2 at this point.  Once the coding is done to the class to keep everything in sync, this should allow us more time to finish the other coding changes.

November 27, 2013 at 12:21 am Leave a comment

Blogging about programming, networking, and computers in general

Welcome to my new blog. Previously, I blogged about PHP at As it happens, I’m doing somewhat less PHP programming now. I’ve also began to do some Ruby programming. I work with just about anything network related (Cisco Routers, Cabletron Switches, Cisco Switches, etc.) Since then, I’ve also switched from a Windows machine as my primary box to a Mac Mini… Then, I switched to an Intel iMac, just after they were introduced. So, there’s no telling what I’ll find interesting to blog about… That’s why I started the Jack of All I.T. blog.

May 2, 2007 at 4:49 pm Leave a comment

Telnet via PHP? Easy, but SSH via PHP?

Writing scripts to telnet using PHP (from the command line) is fairly simple… I have a class around here somewhere that lets you do exactly that, and it’s easy to use and extend… The script can telnet to a device, log in, perform commands, and even react to responses intelligently..

Does anyone have any suggestions for way to script with PHP an interactive SSH session, like mentioned above?

December 18, 2004 at 4:09 pm Leave a comment

FAQ is online

The PHP Sourcery Knowledgebase is now online, live right here and is working well, with almost 100 articles for your viewing and searching pleasure. It is currently hard coded in some areas to work with JaxHosting, which I will need to modify in the upcoming weeks.

I completed updating the FAQ with Security in mind… The online magazine PHP Architect has a section entitled “Security Corner” that I highly recommend, as it pretty much cuts to the chase on security issues with PHP apps.

September 21, 2004 at 4:06 pm Leave a comment

Slow progress

I’ve finished up the basics of the FAQ system.. It now actually works, right down to the search feature… (It doesn’t count up each time an item is viewed or anything too fancy yet. Just basic functionality.)

BUT, the next piece that I must dive into is security… At this point, I’ve not put a lot of effort into securing this application from would-be hackers. Now, it’s not likely that too many people would be interested in hacking your FAQ, but I wouldn’t put it past some to attempt to deface it, requiring you to either restore your database (you did make a backup, didn’t you?) or manually fix the things they messed up.

The biggest issue with security in Web applications is that the data you receive from the user can not *AT ANY TIME* be trusted. I can’t stress this enough. It doesn’t matter what use the variable has, it can probably be exploited if you don’t escape your user input. This goes for any form where they can enter data (search, etc.) as well as anything passed in the URL.

September 13, 2004 at 4:03 pm Leave a comment

Trim text down for the web

I was busy working on the routine to display the results a search in my FAQ web application when I realized that I needed to cut the results short… This was painfully obvious during my testing as one of my test questions has an extremely long answer. Displaying each matching question and answer in its entirety would be a bit much…

Of course, there are simple ways of cutting your text short, but PHP’s built-in functions aren’t very smart about it and will cut the text EXACTLY where you tell it to. This can result in a topic like “Fun things to do with sextants”, if trimmed at 25 characters, to be “Fun things to do with sex”… This type of thing could offend some site visitors, and would likely embarrass some site owners.

In my question to keep from re-inventing the wheel, I ran across a good free routine released by the fine folks at Silver Orange. It intelligently trims text along spaces and accounts for a wide variety of issues that can come up. I was able to easily drop it right into my FAQ project and it works beautifully. I highly recommend it!

September 5, 2004 at 4:02 pm Leave a comment


For probably a year now I’ve been looking at various tools to be able to verify that web services are up and working properly. Most of these tools offer the ability to “ping” a TCP port, basically to see if it is still up. The nicer ones will also let you perform a “content check” to see if a certain string of text appears on the website you are checking.. Some let you check lots of services (HTTP, SMTP, POP3, etc.) I won’t go into the reasons why, but I’ve finally decided that I absolutely need to be running one of these applications, and I need it right now…

Of course, there is a reason why I don’t have one yet… Cost. People who have written these tools are extremely proud of them.

So, I’ve decided to write my own SiteCheck tool in PHP. Here are the requirements:

1. Must work well on a PC that has a somewhat unreliable internet connection. (Check to make sure internet connection is up)
2. Must be able to check a number of sites.
3. Must be able to send an email whenever a problem is found. (One email should contain all sites that failed that attempt, not 4 emails if 4 different sites failed.)

*tick tock tick tock*
Ok, about an hour of coding and testing later, and I have my first version ready…

I was planning to post at least a portion of it here, but until I get my CMS up and running, or come up with some other “code viewer”, I guess I’ll hold off.

I used two arrays, $inet and $siteToCheck to hold data. $inet is strictly for “stable” sites that you expect to always be up and working… Basically, if you can’t get to any of these sites, your internet connection is not working right. The $siteToCheck array is for the sites you are interested in checking out. The index of these arrays is the URL of the site to check (such as and the value of each element is a piece of text that is on the page, such as “Yahoo!”.

A quick function called readWebSite pulls the data in from the remote website and verifies that the “content” is there. If so, you get a true response from this function, otherwise false.

In the main loop of the program, a foreach runs against each element of the $inet array. The first “good” reply tells us that the internet is up, so we set a flag variable accordingly and “break;” out of the foreach loop. No need to check your entire list of “stable” internet sites.

If the Internet is up, we run a foreach against each site in the $siteToCheck array. Any problems are recorded in the $problems variable.

If there were any problems, an email is sent to me to let me know the extent of the issues.

Then, we simply sleep for 15 minutes and repeat…

It would not be too difficult to write a version of this to perform most of your standard communications, as PHP has other protocols that are easily checked, such as SMTP and POP3.

August 25, 2004 at 4:01 pm Leave a comment

The UI Blues

Working on a User Interface is enough to give anyone the blues… Designing the screen layout isn’t easy, and once you do know what you want it to look like, you have to figure out all the fancy SQL statements needed to be able to display the data.

Once you have the SQL statements figured out, you really run into a quandry, unless you have an extremely simple application. To produce a single page of HTML, you may end up with multiple queries per category. So, do you run the risk of performing 30 SQL queries per page-load? There has got to be a better way!

In my case, the better way has involved loading all category data into memory, then iterating through that data to determine sub-category relationships, etc. as needed, instead of performing a SQL query per category to figure that out. This “caching” of data isn’t that difficult, but does move you away from a “pure SQL” mode of thinking. I still have to perform one query per visible category to get a count of all questions in that category and the below sub-categories, but that was expected. Still, this should reduce the number of SQL queries per page-load to about 50% of what it would be otherwise.

Now, you might think that cutting out a query here and there isn’t that big of a deal, but it really is… Anyone who has every been Slashdotted will agree with me on this one. If you suddenly have 10,000 people all trying to hit your page within seconds of each other, your server will be much happier with more efficient code, since it will have to perform the code for each and every request.

August 14, 2004 at 3:58 pm Leave a comment

Older Posts


November 2021

Posts by Month

Posts by Category