As we showed previously with WordPress, detecting the Joomla! version from its source code is also possible. Although not that straight-forward as WordPress.
The best success I had was to use multiple approaches, so if one fails, the code moves to the others. It should be also noted that with some approaches the best you can do is get the approximate Joomla! version, for example, setting it to 3.9.24 will most likely mean 3.9.20+ or event 3.9.10+ depending on the method.
1. Language files
This is the method that returns good results even for very old Joomla! Versions.
The first step you should try is to scrape the /language/en-GB/en-GB.ini
file. On older Joomla! versions it included some strings from the person that made the last production commit (just my guess). So for example you can find strings like:
en-GB.ini 11391 2009-01-04 13:35:50Z ian en-GB.ini 20196 2011-01-09 02:40:25Z ian en-GB.ini 20990 2011-03-18 16:42:30Z infograf768 en-GB.ini 20990 2011-03-18 16:42:30Z infograf768 en-GB.ini 22183 2011-09-30 09:04:32Z infograf768 en-GB.ini 22183 2011-09-30 09:04:32Z infograf768
Each of the above strings corresponds to a particular version. So let’s say you are using Python and you already got the language file’s source code in a var called lang_text
. With the example code below you can get something like:
if lang_text: found_1526 = re.search('en-GB.ini 11391 2009-01-04 13:35:50Z ian', lang_text) found_160 = re.search('en-GB.ini 20196 2011-01-09 02:40:25Z ian', lang_text) found_165 = re.search('en-GB.ini 20990 2011-03-18 16:42:30Z infograf768', lang_text) found_171 = re.search('en-GB.ini 20990 2011-03-18 16:42:30Z infograf768', lang_text) found_173 = re.search('en-GB.ini 22183 2011-09-30 09:04:32Z infograf768', lang_text) found_175 = re.search('en-GB.ini 22183 2011-09-30 09:04:32Z infograf768', lang_text) if found_1526: version = '1.5.26' return version if found_160: version = '1.6.0' return version if found_165: version = '1.6.5' return version if found_171: version = '1.7.1' return version if found_173: version = '1.7.3' return version if found_175: version = '1.7.5' return version
As you can see, we can get pretty exact version numbers with this approach.
The next language file would be the /language/en-GB/en-GB.xml
file. It will be present on most sites. Of course, you can get it only if the server allows direct loading of these files. On some of them that is forbidden.
This XML file contains a “version” node like so:
<metafile version="3.9" client="site"> <name>English (en-GB)</name> <version>3.9.25</version> <creationDate>February 2021</creationDate> <author>Joomla! Project</author> <authorEmail>admin@joomla.org</authorEmail> <authorUrl>www.joomla.org</authorUrl> <copyright> Copyright (C) 2005 - 2020 Open Source Matters. All rights reserved. </copyright> <license> GNU General Public License version 2 or later; see LICENSE.txt </license> <description>en-GB site language</description> <metadata> <name>English (United Kingdom)</name> <nativeName>English (United Kingdom)</nativeName> <tag>en-GB</tag> <rtl>0</rtl> <locale> en_GB.utf8, en_GB.UTF-8, en_GB, eng_GB, en, english, english-uk, uk, gbr, britain, england, great britain, uk, united kingdom, united-kingdom </locale> <firstDay>0</firstDay> <weekEnd>0,6</weekEnd> <calendar>gregorian</calendar> </metadata> <params/> </metafile>
With a simple Python code as:
soup = BeautifulSoup(lang_text,'lxml') if soup: item = soup.find('version') if item is not None: version = item.get_text() return version
you can get the version node’s text content. For example 3.9.25 in our case.
2. Joomla! manifests files
The next thing you could try is to try to scrape the Joomla! manifest file: /administrator/manifests/files/joomla.xml
. If the server allows that to be accessed you will get something like this:
<extension version="3.6" type="file" method="upgrade"> <name>files_joomla</name> <author>Joomla! Project</author> <authorEmail>admin@joomla.org</authorEmail> <authorUrl>www.joomla.org</authorUrl> <copyright> (C) 2005 - 2020 Open Source Matters. All rights reserved </copyright> <license> GNU General Public License version 2 or later; see LICENSE.txt </license> <version>3.9.25</version> <creationDate>February 2021</creationDate> ……………
As you see there is a special node, exactly named “version” as was the case with the language files. The procedure to get the version can be exactly the same as previously explained.
3. Joomla! Generator Meta tag
The generator meta tag is what Joomla! (and other CMSs) insert in the site’s head tag. On the recent versions (3.9+) the generator tag doesn’t contain a version token but on the older Joomla! versions, even the exact version number was included. So for example:
Joomla 1.0+ :
<meta name="Generator" content="Joomla! - Copyright (C) 2005 - 2007 Open Source Matters." />
Joomla 1.5+ :
<meta name="generator" content="Joomla! 1.5 - Open Source Content Management" />
With a simple regex like:
^Joomla!\s+(\*|\d+(?:\.\d+){0,2}(?:\.\*)?
You will be able to get the version part from the content attribute.
4. Joomla! system.css file
The next approach would be to read the system.css file, which on most Joomla! sites can be found under /templates/system/css/system.css
. It comes with the default Joomla! installations.
You could search for two particular strings in this file: “Copyright” and “OpenID icon style”.
For example the string: “Copyright (C) 2005 – 2014 Open Source Matters” would mean the site is 2.5+ and if “OpenID icon style” is found , that would mean the site is Joomla! 1.5+
As you can see, with this approach we can only get approximate, generic versions and not the exact ones.
5. MooTools JS Library
I think it was Joomla! 1.5 when the decision was made to include a core javascript library by default. The chosen library was MooTools. Pretty much dead these days, but it was kind of a big thing back in the day.
Anyway, MooTools.js, because of backward compatibility is still shipped with Joomla! even today. Although starting with Joomla! 3, the primary library included and used by the core is jQuery.
So how can you use the MooTools script to detect the Joomla! version? It’s simple. You just scrape and load the source code of the file /media/system/js/mootools-more.js
and /media/system/js/mootools.js
. And then search for strings like the following:
MooTools={version:’1.12′} MooTools.More={version:”1.3.0.1” MooTools.More={version:”1.3.2.1” MooTools.More={version:”1.4.0.1”
Starting with Joomla! 2.5 the MooTools version that is shipped is 1.4.0.1. and it stays that way until the latest 3.9+ Joomla! Versions.
Some sample Python code:
js_text = response.text if js_text: js_text = js_text.strip() found_15 = re.search('MooTools=\{version:\'1\.12\'}', js_text) found_16 = re.search('MooTools\.More={version:\"1\.3\.0\.1\"', js_text) found_17 = re.search('MooTools\.More={version:\"1\.3\.2\.1\"', js_text) if found_15 is not None: version = '1.5' return version elif found_16 is not None: version = '1.6' return version elif found_17 is not None: version = '1.7' return version
Since 1.4.0.1 is included in both 2.5 and 3.+ versions, it is not very useful for version detection.
6. TinyMCE Versions
As you might know, Joomla!’s HTML editor of choice was always TinyMCE. Its installation comes with an XML manifest file, that you can load through: /plugins/editors/tinymce/tinymce.xml
.
This file contains a <version> node, which contains TinyMCE version installed. Like so:
<extension version="3.2" type="plugin" group="editors" method="upgrade"> <name>plg_editors_tinymce</name> <version>4.5.12</version> <creationDate>2005-2020</creationDate> <author>Tiny Technologies, Inc</author> <authorEmail>N/A</authorEmail> <authorUrl>https://www.tiny.cloud</authorUrl> <copyright>Tiny Technologies, Inc</copyright> <license>LGPL</license> <description>PLG_TINY_XML_DESCRIPTION</description> <files> <filename plugin="tinymce">tinymce.php</filename> <folder>fields</folder> …………….
From my experience, the best results with this method are achieved with Joomla! 3+ versions. The mapping of TinyMCE versions and Joomla! versions will look like this (Python with BeautifulSoup module):
tinymce_text = response.text soup = BeautifulSoup(tinymce_text,'lxml') if soup: item = soup.find('version') if item is not None: tiny_version = item.get_text() if tiny_version == '3.5.6': version = '3.1' elif tiny_version == '4.0.10': version = '3.2.0' elif tiny_version == '4.0.12': version = '3.2.2' elif tiny_version == '4.0.18': version = '3.2.4' elif tiny_version == '4.0.22': version = '3.3.0' elif tiny_version == '4.0.28': version = '3.3.6' elif tiny_version == '4.1.7': version = '3.4.1' elif tiny_version == '4.3.3': version = '3.5.0' elif tiny_version == '4.3.12': version = '3.6.0' elif tiny_version == '4.4.0': version = '3.6.1' elif tiny_version == '4.4.3': version = '3.6.5' elif tiny_version == '4.5.6': version = '3.7.0' elif tiny_version == '4.5.7': version = '3.8.0' elif tiny_version == '4.5.8': version = '3.9.0' elif tiny_version == '4.5.11': version = '3.9.10' elif tiny_version == '4.5.12': version = '3.9.24'
7. README.txt file
In the root of every Joomla! installation you will find the Readme.txt file. This is a file where you can find the basic information about the CMS itself. Like description, installation procedures and links, support links, etc.
But it also contains something more. Like for example the string: version history:
1- What is this? * This is a Joomla! installation/upgrade package to version 3.x * Joomla! Official site: https://www.joomla.org * Joomla! 3.9 version history - https://docs.joomla.org/Special:MyLanguage/Joomla_3.9_version_history * Detailed changes in the Changelog: https://github.com/joomla/joomla-cms/commits/staging
You can do a basic search for this string with a regex like this (Python):
version_match = re.search(r"Joomla_(\d\.\d)_version_history", readme_text.strip());
As it is obvious, you can only get the generic version with this, like 3.9, and not minor versions like 3.9.24. But depending on your intention, that could be more than enough.
8. jQuery Version
From my experience, you can take this approach to detect some generic Joomla! 3+ versions, like 3.5.0, 3.6.0 or 3.9.20
File to scrape: /media/jui/js/jquery.min.js
Example regexes:
/\*!\s+jQuery\s+v(\d\.\d+\.\d+ /\*!\s+jQuery\s+v(\d\.\d+\.\d+)-joomla
Mapping:
jQuery version | Joomla! version |
1.11.3 | 3.5.0 |
1.12.4 | 3.6.0 / or 3.9.20 depending on the regex above |
Bonus tip
If all of the above is not enough for your project requirements, then you may want to try some online service like WhatCMS. They have quite nice API you can use, and the results are almost always correct.
If you happen to know some other way of Joomla! version detection, I would be glad to hear about it in the comments section below.