Task: write a script that can download a new version of yourself from a remote server and update itself.
The practice of auto-updates is widely used among desktop clients and operating systems, but it is rarely found on the web. However, for scripts, where one installation ensures the operation of one resource (and these are, in fact, all the scripts you put on hosting), the automated ability to install updates is no less important than for desktops. Of course, this has nothing to do with web services.
')
Technically, updating the script is not so difficult - download the update from a remote server and install it on top of a working version - however, there are some nuances. We, in Webasyst, have been practicing the installation of remote updates for a long time and have gained a lot of experience with all sorts of server hosting configurations. Share experience.
This is not a tutorial, so here is the final version of the script:
www.webasyst.com/etc/ru/selfupdate-1 (script index.php; ≈20 KB).
The script contains
the selfUpdate class , which performs the update itself (downloads the updated version of the index.php file and replaces it with the currently running one).
Under the cat we consider how the update process is organized and what problems may arise during the upgrade.
How to run the script?
Just download the script and upload it to a folder on the server. By running the script in a browser, you will see the Hello World heading and script update buttons.
In order for the script update to work, you need to enable
write permissions for the root folder where the script is installed. This is necessary because the script will create a subdirectory in this folder to download the updated script from a remote server into it. If you run the script on a localhost in Windows (for example, on the basis of the Denver package), then you do not need to grant access rights - everything will work by itself.
The index.php script downloads its updated version from the server
as is (not in the archive) and replaces itself with it. Updating scripts in which there are a lot of files, in reality, differs only in that the archive with scripts is downloaded from the server. Otherwise, everything works in the same way: uploaded files - updated files.
Download file from remote server
For updating the script goes to the same address that was presented above (http://www.webasyst.com/etc/ru/selfupdate-1/). This update
source gives an “update” as an attachment (for clarity, we made two variations: V1 displays the message Hello world, and V2 shows the sum of three random numbers).
Downloading a file from a remote server from a script is possible in two ways:
Via fopen (): Yes, through normal fopen (). But for this function to work, it is necessary that the parameter allow_fopen_url = On be set in the PHP settings (php.ini) and HTTP is in the list of supported protocols.
Via cURL : This option is preferable, as it is more flexible. For example, when using cURL, you can make a resumption of the download in case it was interrupted.
Upgrade a running script
The file of the PHP script that is currently running is
not blocked by the system by writing, and therefore it can be overwritten. In this regard, the installation of the update in our example is as follows: the file is downloaded to a separate subfolder (/ updates / download /), whether the file is correctly loaded (matches the size of the downloaded file to the size stated in the response headers, as well as checking the md5 file ), and then the working index.php script is overwritten with the updated file.
In the case of a single file, everything is trivial: downloaded and overwritten. It is more interesting when an archive with scripts is downloaded from the server. More interesting is the fact that there are three options (strategies) for unpacking:
1) the downloaded archive can be unpacked on top of working scripts: a good option, but at the time of unpacking it will break the system, it will be downtime;
2) copy the current version of working scripts to a temporary folder, unpack the downloaded archive on top of this folder, move the working version to the backups directory, and update code instead: the option is bad because it preserves obsolete files;
3) unpack the archive into a separate folder, and then replace the working folder with an updated version: this option is most interesting because it implies the least downtime in the work of the scripts.
Problems
The main problems encountered during the upgrade:
- max_input_time (restriction on the time of I / O operations): downloading files of a significant amount may not meet the maximum allowable time;
- max_execution_time: the update process can rest against the limit on the total running time of the script. The peculiarity is that this cannot happen when downloading a file from a remote server, since PHP does not consider time for file operations (although there are features in Windows systems), however, the limitation becomes critical when
unpacking archives of considerable size;
- availability of the update server: in addition to the lack of a suitable transport for downloading updates (via fopen or curl), there may be network problems (DNS, routing, firewall);
- disconnections with the server during the file download: it is necessary to check the integrity of the file after downloading, but for this the server that issues the update must be able to give the md5 hashes to the files.
These problems are typical for downloading
large archives. For updating one twenty-lb index.php this is not relevant (except for the need to check the integrity of the downloaded file).
We plan to consider downloading large archives in the next post, where we will present the second version of the selfUpdate class with support for downloading files (with the progress bar!), Unpacking the archive and resuming the download in case of a failure.