Skip to content

Instantly share code, notes, and snippets.

@renekreijveld
Last active September 17, 2021 13:12
Show Gist options
  • Save renekreijveld/6112359 to your computer and use it in GitHub Desktop.
Save renekreijveld/6112359 to your computer and use it in GitHub Desktop.
This bash script will update your Joomla 2.5/3.1 website to the latest Joomla version. It does this by automatically downloading the correct update zipfile from Joomla.org. The script also executes the sql update commads (if needed). If specified joomlaupdate will make a backup of your website and database before updating. Joomlaupdate can also …
#!/bin/sh
# joomlaupdate
# Updates your Joomla 2.5/3.1 website to the latest version.
#
# Usage: joomlaupdate [-s] [-b] [-h] [-l]
#
# Default action is verbose on, no backup.
# -s Silent. Do not display any informational messages.
# -b Backup. Create a backup before updating.
# -l Log. Write messages to logile /var/log/joomlaupdate.log.
# -h Help. Display this info.
# Run joomlaupdate at the root of your website, where the configuration.php is.
#
# Copyright 2013 Rene Kreijveld - [email protected]
#
# This program is free software; you may redistribute it and/or modify it.
#
# Necessary tools for this script: wget, unzip, tar and perl. Install these if they are not available.
#
# Version history
# 1.0: - Initial version.
# 1.1: - Added support for Joomla 3.0 and 3.1.
# - Better logging, added -l parameter.
# - Clode cleanup.
# 1.2: - Added backup path (suggestion by Remco Janssen).
# 1.3: - Removed support for Joomla 3.0.
# - Fixed bug of not all SQL updates being run (thanks Xavier Pallicer).
# 1.4: - Added updating of #__schemas table. This was missing (thanks Xavier Pallicer).
# 1.5: - Added updating of #__extensions table. This was missing (thanks Xavier Pallicer).
#
# general variables
version=1.5
logfile=/var/log/joomlaupdate.log
backuppath=../
# find mysql socket
if [ -S /var/lib/mysql/mysql.sock ]; then
mysock=/var/lib/mysql/mysql.sock
elif [ -S /var/run/mysqld/mysqld.sock ]; then
mysock=/var/run/mysqld/mysqld.sock
elif [ -S /Applications/XAMPP/xamppfiles/var/mysql/mysql.sock ]; then
mysock=/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock
elif [ -S /tmp/mysql.sock ]; then
mysock=/tmp/mysql.sock
fi
# display usage information
usage() {
echo "joomlaupdate version $version, written by Rene Kreijveld."
echo " "
echo "Usage: joomlaupdate [-s] [-b] [-l] [-h]"
echo " "
echo "Default action is verbose on, no backup."
echo "-s Silent. Do not display any informational messages."
echo "-b Backup. Create a backup before updating."
echo "-l Log. Write messages to logile /var/log/joomlaupdate.log."
echo "-h Help. Display this info."
echo " "
echo "Run joomlaupdate at the root of your website, where the configuration.php is."
echo " "
exit 0
}
# process the arguments
while getopts sblh opt
do
case "$opt" in
s) silent="yes";;
b) backup="yes";;
l) logging="yes";;
h) usage;;
\?) usage;;
esac
done
# echo out messages to screen and/or logfile
eout() {
mesg=$1
stdout=$2
# if logfile doesn't exist, create it first
if [ ! -f "$logfile" ]; then
touch $logfile
fi
# if not silent display message
if [ "$silent" != "yes" ]; then
if [ ! -z "$stdout" ]; then
echo "$mesg"
fi
fi
# if logging enabled message to logfile
if [ "$logging" == "yes" ]; then
echo "$mesg" >> $logfile
fi
}
# grab information from Joomla 2.5/3.1 configuration.
do_joomla2531() {
sitename=`grep '$sitename =' configuration.php | cut -d \' -f 2 | sed 's/ /_/g'`
versr=`grep '$RELEASE' libraries/cms/version/version.php | cut -d \' -f 2`
versd=`grep '$DEV_LEVEL' libraries/cms/version/version.php | cut -d \' -f 2`
verss=`grep '$DEV_STATUS' libraries/cms/version/version.php | cut -d \' -f 2`
database=`grep '$db =' configuration.php | cut -d \' -f 2`
dbuser=`grep '$user =' configuration.php | cut -d \' -f 2`
password=`grep '$password =' configuration.php | cut -d \' -f 2`
host=`grep '$host =' configuration.php | cut -d \' -f 2`
prefix=`grep '$dbprefix =' configuration.php | cut -d \' -f 2`
}
# cleanup all temporary files
do_cleanup() {
if [ -f list1.xml ]; then
rm -f list1.xml
fi
if [ -f list2.xml ]; then
rm -f list2.xml
fi
if [ -f update.zip ]; then
rm -f update.zip
fi
if [ -f tmp/sqlupdate.sql ]; then
rm -f tmp/sqlupdate.sql
fi
if [ -f $backuppath$database.sql ]; then
rm -f $backuppath$database.sql
fi
if [ -f joomla.xml ]; then
rm -f joomla.xml
fi
}
# create a full backup of the joomla website
do_backup() {
# dump the database to a .sql file
eout "Backup requested." 1
eout "Creating database backup." 1
# check if sql dumpfile already exists
if [ -f $backuppath$database.sql ]; then
eout "Database backup file $backuppath$database.sql already exists. Exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 1
fi
# create mysqldump
if mysqldump --skip-opt --add-drop-table --add-locks --create-options --disable-keys --lock-tables --quick --set-charset --host=$host --user=$dbuser --password=$password --socket=$mysock $database > $backuppath$database.sql; then
eout "$backuppath$database.sql created." 1
else
eout "Error creating database dump, exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 1
fi
# check if tgz backupfile doesn't already exist
if [ -f $backuppath$sitename.tgz ]; then
eout "Backup file $backuppath$sitename already exists. Exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 1
fi
# create the .tgz backup
eout "Creating files backup." 1
tar czf $backuppath$sitename.tgz .htaccess *
eout "Your website backup is ready in $backuppath$sitename.tgz." 1
eout " " 1
}
get_joomla_info() {
# Grab owner and group of current configuration.php
owner=`ls -l configuration.php | awk '{print$3}'`
group=`ls -l configuration.php | awk '{print$4}'`
# Testing for Joomla version 2.5 or 3.1
if [ -f libraries/cms/version/version.php ]; then
release=`grep '$RELEASE' libraries/cms/version/version.php | cut -d \' -f 2`
if [ "$release" == "2.5" ]; then
# grab information about this 2.5 website
do_joomla2531
fi
if [ "$release" == "3.1" ]; then
# grab information about this 3.1 website
do_joomla2531
fi
fi
}
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
if [ "$logging" == "yes" ]; then
eout " "
eout "$datestamp: Start joomlaupdate."
fi
eout "joomlaupdate version $version, written by Rene Kreijveld." 1
eout " " 1
# if configuration.php present then proceed
if [ -f configuration.php ]; then
# display information about current website
get_joomla_info
eout "This Joomla! website:" 1
eout "Sitename : $sitename" 1
eout "Version : $versr.$versd" 1
eout "DB Name : $database" 1
eout "DB User : $dbuser" 1
eout "DB Password : $password" 1
eout "DB Host : $host" 1
eout "DB Prefix : $prefix" 1
eout "Path : `pwd`" 1
eout "Owner : $owner" 1
eout "Group : $group" 1
eout " " 1
# store old development version
oldversd=$versd
oldversfull="$versr.$versd"
# get update list from joomla.org
updatelist=`grep "<server" -m 1 administrator/manifests/files/joomla.xml | awk -F"<server type=\"collection\">" '{print$2}' | awk -F"</server>" '{print$1}'`
wget $updatelist -q -O list1.xml >/dev/null 2>/dev/null
updatelist="unknown"
# grab information about update file and latest version number
if [ "$versr" == "2.5" ]; then
updatelist=`grep "targetplatformversion=\"2.5\"" -m 1 list1.xml | awk -F"detailsurl=\"" '{print$2}' | awk -F"\" />" '{print$1}'`
newversion=`grep "targetplatformversion=\"2.5\"" -m 1 list1.xml | awk -F"version=\"" '{print$2}' | awk -F"\"" '{print$1}'`
fi
if [ "$versr" == "3.1" ]; then
updatelist=`grep "targetplatformversion=\"3.1\"" -m 1 list1.xml | awk -F"detailsurl=\"" '{print$2}' | awk -F"\" />" '{print$1}'`
newversion=`grep "targetplatformversion=\"3.1\"" -m 1 list1.xml | awk -F"version=\"" '{print$2}' | awk -F"\"" '{print$1}'`
fi
# this website is not 2.5/3.1, exiting
if [ "$updatelist" == "unknown" ]; then
eout "This Joomla version cannot be updated. Exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 0
fi
# if current version number equals latest version number no update is necessary
if [ "$versr.$versd" == "$newversion" ]; then
eout "This Joomla website is already up-to-date. Exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 0
else
# if backup needed, create backup first
if [ "$backup" == "yes" ]; then
do_backup
fi
eout "This website will be updated to version $newversion." 1
wget $updatelist -q -O list2.xml >/dev/null 2>/dev/null
# get url of update zipfile
updatefile=`grep "x_to_$newversion" -m 1 list2.xml | awk -F">" '{print$2}' | awk -F"</downloadurl" '{print$1}'`
eout "Downloading updatefile: $updatefile." 1
# download update zipfile
wget $updatefile -O update.zip >/dev/null 2>/dev/null
# Updating files
eout "Extracting zipfile, updating files." 1
# update files
unzip -q -o update.zip
# retrieve new version info
get_joomla_info
# set rights
eout "Setting file ownership." 1
chown -R $owner:$group .htaccess *
# execute all mysql updates frm previous version to current version
oldversd=`expr $oldversd + 1`
eout " " 1
for (( u=oldversd; u<=versd; u++ )); do
for sqlfile in `ls administrator/components/com_admin/sql/updates/mysql/$versr.$u*sql`; do
eout "Running SQL update $sqlfile." 1
# copy sql update file to temporary directory
cp $sqlfile tmp/sqlupdate.sql
# modify prefix so it matches for this website
perl -pi -e "s/#__/$prefix/g" tmp/sqlupdate.sql
# run sql updates
if mysql --host=$host --user=$dbuser --password=$password --socket=$mysock $database < tmp/sqlupdate.sql
then
eout "SQL update completed." 1
rm -f tmp/sqlupdate.sql
else
eout "Error running SQL update. Exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 1
fi
done
done
# fix joomla version in #__schema and #__extension tables
sql="UPDATE #__schemas SET version_id = \"$versr.$versd\" WHERE extension_id = 700;"
echo $sql | sed -e "s/#__/$prefix/" > tmp/sqlupdate.sql
sql="UPDATE #__extensions SET manifest_cache = REPLACE(manifest_cache, '\"version\":\"$oldversfull\"', '\"version\":\"$versr.$versd\"') WHERE extension_id = 700;"
echo $sql | sed -e "s/#__/$prefix/" >> tmp/sqlupdate.sql
if mysql --host=$host --user=$dbuser --password=$password --socket=$mysock $database < tmp/sqlupdate.sql
then
eout "Succesfully updated #__schemas and #__extension tables." 1
rm -f tmp/sqlupdate.sql
else
eout "Error updating #__schemas and #__extensions tables. Exiting." 1
do_cleanup
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
exit 1
fi
eout " " 1
eout "Cleaning up temporary files." 1
do_cleanup
# update and display joomla info
eout " " 1
eout "Joomla update finished. Website info:" 1
eout "Sitename : $sitename" 1
eout "Version : $versr.$versd" 1
eout "Do not forget to update your language files." 1
# finished
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
fi
else
eout "File configuration.php not found. Are you at the root of the site?" 1
datestamp=`date +"%d-%m-%Y, %H:%M:%S"`
eout "$datestamp: End joomlaupdate."
eout " "
exit 1
fi
@renekreijveld
Copy link
Author

joomlaupdate now runs the required SQL updates correctly.
So if you upgrade from 2.5.a to 2.5.b, then all SQL updates from a+1 to b are executed.

@xpallicer
Copy link

Hello Rene,

I have checked and I see the same error, I think problem is at _schemas table.

I've checked the error in Joomla! com_installer, and I found in models/database.php, getSchemaVersion function is causing the problem.

I think that the version shoud be updated to the latest version installed, I mean UPDATE #__schemas table when update is ready.

Maybe this can cause further problems, but I don't think so. Maybe somebody with more knowledge can help!

Regards!

@xpallicer
Copy link

UPDATE #__schemas SET version_id = 'NEWVERSION' WHERE extension_id = 700

I think this should do the trick

@renekreijveld
Copy link
Author

Update of #__schemas table is now added to the script.

@xpallicer
Copy link

Hello Rene,

I've tested and found one more prob: "Database update version (2.5.11) does not match CMS version (2.5.14).", originated by getUpdateVersion function, in the same database.php file.

It can be fixed with a query like this:

UPDATE #__extensions SET manifest_cache = REPLACE(manifest_cache, '"version":"OLDV"', '"version":"NEWV"') WHERE extension_id = 700;

I'm sorry I always carry bad news! :S

@renekreijveld
Copy link
Author

Gat the patch for #__extensions now also in!

@cavo789
Copy link

cavo789 commented Feb 14, 2014

Sounds really really great ! I don't need this script but just want to say you "Good job and thanks for the sharing!!!"

@AndyGaskell
Copy link

I really liked the sound of this script, and the code looks good, however, I tried to update a site from 3.3.3 to 3.4.3 and it just returned "This Joomla version cannot be updated. Exiting.".

I think this is just because maybe the newer Joomla versions do things a little differently, but I'll try and see if I can fix it.

@tonypartridge
Copy link

It's now built into Akeeba and myjoomla.com for automatic updating.

@raua
Copy link

raua commented Feb 19, 2016

Hi @renekreijveld, @xpallicer and @AndyGaskell did you guys fix this? I'm trying to fix this too, because all versions between 3.2 and 3.4.8 have security issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment