Search
  • Sotware by
  • Christoph Amthor
Search Menu

How To Use Piwik To Log Version Statistics From An Update Checker

Photo by Pixapopz (Pixabay)

Some of my plugins send queries to my server to check if a later version is available. So I thought about a possibility to log and evaluate the information that is sent along with these queries – most importantly the currently installed plugin version. This would give me an idea about which versions are still in use. Of course, the data doesn’t represent the real distribution of version since it depends on which plugins query your server how often.

Piwik statistics deployed versions

Retrieving and saving the data didn’t seem to be the problem, but then I needed to process it. You can feed the table into a statistics package, or you can just use a free open source analytics software: Piwik can easily be used to collect and analyse data like visits, or even custom events and categories. Usually it works through a Javascript tracking code on a website, but you can also send the events directly from PHP.

In order not to overburden your server with requests and to create a somewhat equal distribution of requests over time, I recommend to cache the retrieved version information in the client software.

In my plugin I also added the option to disable automatic checks in the plugin. Some users might not want the plugin to “call home”. If you want to anonymize the stats, you can also tell Piwik to reduce the accuracy of the location retrieved from the IP address.

Preparations

  1. First of all, you need of course a working Piwik installation. Log in and click on “Add a new website”. Give it any name you want, for example “Update Checks”. Note down the ID of this website.
  2. Still in Piwik, install and activate the plugin “Custom Dimensions”. Then go to the settings and create a custom dimension for visits (not actions) called “Versions”. Make sure you create it for that new website. Note down the identifier of this dimension – a string like “dimension1”. If you want to track the versions of several packages, you can include their names here: “1st SW Versions”.
  3. Then you will need the file PiwikTracker.php that you find in the downloaded Piwik files (for self-hosting), in the folder “vendor/piwik/piwik-php-tracker/”. It must be includable by the script below. So you possibly have to copy it over to the server where you receive the clients’ requests. Piwik can be installed somewhere else and must only be reachable by HTTP.

The Script

Our script starts1 by reading the input from the query sent by the plugin. The format of that query would be:

https://www.example.com/update-check.php?package=my-great-plugin&version=1.0&hash=abc123...

You can of course report also the currently used PHP version and other useful indicators – but remember that your users probably don’t want to give away other than very basic information.2

/**
* package information, something like: my-great-plugin - e.g. a plugin identifier
*/
if ( isset( $_GET['package'] ) ) {
  /**
  * Retrieve the query value.
  */
  $package_query = $_GET['package'];

  /**
  * Sanitize the data and limit the length. (Adjust it as required.)
  */
  preg_match( '/^([A-Za-z0-9-]{1,20})$/', $package_query, $package_matches );
}

if ( !empty( $package_matches[0] ) ) {
  $package = $package_matches[0];
} else {
  $package = 'tag-groups-premium';
}

The same for the version number, which comes as a string:

/**
* currently installed version number
*/
if ( isset( $_GET['version'] ) ) {
  /**
  * Retrieve the query value.
  */
  $version_query = $_GET['version'];

  /**
  * Sanitize the data and limit the length. (Adjust it as required.)
  */
  preg_match( '/^([A-Za-z0-9-_. ]{1,20})$/', $version_query, $version_matches );
}

if ( !empty( $version_matches[0] ) ) {
  $version = $version_matches[0];
} else {
  $version = 'unknown';
}

And a hash that identifies the requester across several visits. You can for example apply md5() on the client’s URL in order to anonymize it.

/**
* unique site ID
*/
if ( isset( $_GET['hash'] ) ) {
  /**
  * Retrieve the query value.
  */
  $hash_query = $_GET['hash'];

  /**
  * Sanitize the data and limit the length. (Adjust it as required.)
  */
  preg_match( '/^([A-Za-z0-9]{1,32})$/', $hash_query, $hash_matches );
}

if ( !empty( $hash_matches[0] ) ) {
  $hash = $hash_matches[0];
} else {
  $hash = '';
}

Then include the PiwikTracker class and feed it with data. Packages will be reported as “Page Titles”.

/**
* Adjust the path as needed.
*/
require_once "./PiwikTracker.php";

/**
* Insert the URL of your Piwik installation.
*/
PiwikTracker::$URL = 'https://stats.example.com/';

/**
* Insert the ID of the website in your Piwik installation.
*/
$piwikTracker = new PiwikTracker( 1 );

/**
* Insert an API token with at least Admin permission, available in the Piwik Settings
*/
$piwikTracker->setTokenAuth( 'aaabbcc' );

/**
* If we have a $hash, we use it to identify the visitor across multiple visits.
*/
if ( !empty( $hash ) ) {
  $piwikTracker->setUserId( $hash );
}

/**
* Replace 'dimension1' with the identifier of the custom dimension that you created before.
* Add more packages as needed with the respective dimension value.
*/
switch ($package) {
  case 'my-great-plugin': $dimension = 'dimension1'; break;
  default: $dimension = ''; break;
}
$piwikTracker->setCustomTrackingParameter( $dimension, $version );

/**
* Now we can send the tracker request via http, submitting also the package name.
*/
$piwikTracker->doTrackPageView( $package );

Goal “Update Available”

Piwik goal update availableAdditionally, you can check the reported version against the latest available version and, if the client lags behind, trigger a goal for Piwik. That way you can easily identify requests of clients who should be updating.

In Piwik, create a goal “Update Available” and choose manual triggering, to be triggered only once per visit. Note down the ID of that goal, you will need it as argument for doTrackGoal().

/**
* If the user's version is out-of-date, trigger a goal.
* Fill in the ID of the goal.
*/
if ( version_compare( $version, $latest_available_version ) == -1 ) {
  $piwikTracker->doTrackGoal( 1 );
}

Alert Users About Available Updates

Finally, you can send back the latest version number to the client. I do it by echoing a JSON-formatted array containing the plugin name, the latest version number, and a link to a download.

header('Content-Type: application/json');
echo json_encode( $version_info_array );

The client plugin reads the JSON, decodes it to an array and uses again version_compare to find out if it should report an available update.

Final Thoughts

As mentioned before, the largest shortcoming is that the statistics will be distorted by irregular frequencies how often users check for updates. You can, however, mitigate this factor by using some kind of cron on the client side so that you try to distribute their requests equally over a longer time span.

Please let me know in the comments if you need more clarification, found a flaw or have further ideas.

 

EDIT: The article was extended to allow for many packages to be tracked.

Photo by Pixapopz (Pixabay)

Show 2 footnotes

  1. You may also want to suppress error reporting.
  2. According to legislation in some places you even need their consent.
Share
  • 5
    Shares
  • 5
    Shares

Leave a Comment

Required fields are marked *.