root/trunk/common/mvblog_upgrade.php

Revision 776, 11.2 KB (checked in by michiel, 9 months ago)

update copyright year.

Closes #180

Line 
1<?php
2/**
3 * MvBlog -- An open source no-nosense blogtool
4 *
5 * Copyright (C) 2005-2008, Michiel van Baak
6 * Michiel van Baak <mvanbaak@users.sourceforge.net>
7 *
8 * See http://dev.mvblog.org for more information on MvBlog.
9 * That page also provides Bugtrackers, Filereleases etc.
10 *
11 * This program is free software, distributed under the terms of
12 * the GNU General Public License Version 2. See the LICENSE file
13 * at the top of the source tree.
14 *
15 * @package MvBlog
16 * @author Michiel van Baak
17 * @version %%VERSION%%
18 * @copyright 2005-2008 Michiel van Baak
19 */
20/*
21 * Start the autoloader, so we never have to include anything
22 */
23require_once("mvblog_autoloader.php");
24$mvblog_AutoLoader = new mvblog_AutoLoader();
25
26$pathInfo = pathinfo(__FILE__);
27$mvblog_AutoLoader->registerPath($pathInfo["dirname"], "%s.php", mvblog_AutoLoader::OPT_LOWERCASE);
28
29// Register the AutoLoader object as the autoloader.
30function __autoload($className) {
31  global $mvblog_AutoLoader;
32  $mvblog_AutoLoader->autoload($className);
33}
34
35/* Start heavy error reporting if we're on a dev site */
36MvBlog_debug::start_development(False);
37
38/* Read the configuration file */
39$configfile = dirname(dirname(__FILE__)."../")."/conf/mvblog.ini";
40$availSettings = array(
41    "general" => array(
42        "debug"    => array("type" => mvblog_IniFileReader::TYPE_BOOL,   "default" => "no"),
43    ),
44    "database" => array(
45        "database" => array("type" => mvblog_IniFileReader::TYPE_STRING, "default" => "mvblog"),
46        "hostname" => array("type" => mvblog_IniFileReader::TYPE_STRING, "default" => "localhost"),
47        "username" => array("type" => mvblog_IniFileReader::TYPE_STRING, "default" => "mvblog"),
48        "password" => array("type" => mvblog_IniFileReader::TYPE_STRING, "default" => "mvblog"),
49        "type"     => array("type" => mvblog_IniFileReader::TYPE_STRING, "default" => "mysql"),
50    ),
51);
52$config = new mvblog_IniFileReader($availSettings, $configfile);
53/**
54 * Uprade mvblog to the latest version
55 */
56Class Mvblog_upgrade extends Mvblog_common {
57    /* variables */
58    public $lastpatch = 0;
59    public $lang;
60    /* methods */
61    /* __construct {{{ */
62    /**
63     * Class constructor
64     */
65    public function __construct() {
66        parent::__construct("plugins/", 0, 1);
67    }
68    /* }}} */
69    /* get_patchfiles {{{ */
70    /**
71     * Find out what patchfiles we need to commit.
72     *
73     * @param string $mode Can be svn or release and is used to pick the filenameformat.
74     * @return array Patchfiles that should be applied to the database
75     */
76    public function get_patchfiles($mode = "release") {
77        /* get current database version */
78        if (!array_key_exists("dbversion", $this->settings))
79            $current_version = 0;
80        else
81            $current_version = $this->settings["dbversion"];
82        /* read the db patchfiles into an array */
83        $patchfiles = array();
84        if ($dh = opendir(sprintf("upgrades/%s", $this->db->phptype))) {
85            while (false !== ($v = readdir($dh))) {
86                if (!is_dir($v) && $v != "README") {
87                    if ($mode == "release") {
88                        if (strpos($v, "to") && substr($v, 0, strpos($v, "to")) >= $current_version)
89                            $patchfiles[] = $v;
90                    } else {
91                        if (!strpos($v, "to") && basename($v, ".php") > $current_version)
92                            $patchfiles[] = $v;
93                    }
94                }
95            }
96        }
97        return $patchfiles;
98    }
99    /* }}} */
100    /* sql_addslashes {{{ */
101    /**
102     * Better addslashes for SQL queries.
103     * Taken from phpMyAdmin and modified by me.
104     */
105    function sql_addslashes($a_string = '', $is_like = FALSE) {
106        if ($is_like)
107            $a_string = str_replace('\\', '\\\\\\\\', $a_string);
108        else
109            $a_string = str_replace('\\', '\\\\', $a_string);
110        $a_string = str_replace('\"', '\\\"', $a_string);
111        return str_replace('\'', '\\\'', $a_string);
112    }
113    /* }}} */
114    /* create_backups {{{ */
115    /**
116     * Create a database backup before running the pathes against it so we can rollback when something goes wrong
117     */
118    public function create_backups() {
119        $backuplocation = "backups/";
120        $dbname         = $this->db->database_name;
121        if (!is_dir($backuplocation) && !is_writable($backuplocation))
122            die("Backupdir not available. Please create a directory 'backups' and give the webserver user write permissions on it.");
123        // make backup
124        switch ($this->db->phptype) {
125        case "sqlite" :
126            //copy old database
127            $src = sprintf("db/%s.db", $dbname);
128            $dst = sprintf("backups/%s-%s.db", $dbname, date("YmdHi"));
129            if (copy($src, $dst))
130                return true;
131            else
132                return false;
133            break;
134        case "mysql" :
135            //create database dump
136            return $this->_mysql_backup_db($dbname, $backuplocation);
137            break;
138        case "pgsql" :
139            //create database dump
140            return $this->_psql_backup_db($dbname, $backuplocation);
141            break;
142        default :
143            die("unknown database type. Please report on http://dev.mvblog.org");
144            break;
145        }
146    }
147    /* }}} */
148    /* _mysql_backup_db {{{ */
149    /**
150     * Create mysql backup
151     *
152     * @param string $database The database name to backup
153     * @param string $backuplocation The directory to store the backup in
154     * @return bool true on success, false on failure
155     */
156    private function _mysql_backup_db($database, $backuplocation) {
157        //variable to hold the database
158        $dbdata  = "-- MvBlog upgrade backup dump\n";
159        $dbdata .= "--\n";
160        $dbdata .= sprintf("-- Host: %s\n", $this->db->dsn["hostspec"]);
161        $dbdata .= sprintf("-- Database: %s\n", $database);
162        $dbdata .= sprintf("-- Dump started on %s\n\n", date("Y-m-d H:i:s"));
163        $dbdata .= "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n";
164        $dbdata .= "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n";
165        $dbdata .= "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n";
166        $dbdata .= "/*!40101 SET NAMES utf8 */;\n";
167        $dbdata .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n";
168        $dbdata .= "/*!40103 SET TIME_ZONE='+00:00' */;\n";
169        $dbdata .= "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n";
170        $dbdata .= "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n";
171        $dbdata .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n";
172        $dbdata .= "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n";
173        // get the tables in the database
174        $sql = "SHOW TABLES";
175        $res = $this->db->query($sql);
176        while ($row = $res->fetchRow()) {
177            $table = $row[0];
178            $dbdata .= sprintf("--\n-- Table structure for table '%s'\n--\n\n", $table);
179            $dbdata .= sprintf("DROP TABLE IF EXISTS %s;\n", $table);
180            $q = sprintf("SHOW CREATE TABLE %s", $table);
181            $r = $this->db->query($q);
182            while ($tabledata = $r->fetchRow()) {
183                $dbdata .= $tabledata[1].";\n\n";
184            }
185            $dbdata .= sprintf("--\n-- Dumping data for table '%s'\n--\n\n", $table);
186            $dbdata .= sprintf("LOCK TABLES `%s` WRITE;\n", $table);
187            $dbdata .= sprintf("/*!40000 ALTER TABLE `%s` DISABLE KEYS */;\n", $table);
188
189            // get table structure
190            $q = sprintf("DESCRIBE %s", $table);
191            $r = $this->db->query($q);
192            $tablestruct = array();
193            while ($ts = $r->fetchRow(MDB2_FETCHMODE_ASSOC)) {
194                $tablestruct[] = $ts;
195            }
196            // find fields that dont need ' as data enclosure
197            $ints = array();
198            foreach ($tablestruct as $struct) {
199                if (strpos($struct["type"], "bigint") === 0 ||
200                    strpos($struct["type"], "int") === 0 ||
201                    strpos($struct["type"], "mediumint") === 0 ||
202                    strpos($struct["type"], "smallint") === 0 ||
203                    strpos($struct["type"], "tinyint") === 0 ||
204                    strpos($struct["type"], "timestamp") === 0)
205                        $ints[strtolower($struct["field"])] = 1;
206            }
207            $q = sprintf("SELECT * FROM %s", $table);
208            $r = $this->db->query($q);
209            // \x08\\x09, not required
210            $search = array("\x00", "\x0a", "\x0d", "\x1a");
211            $replace = array('\0', '\n', '\r', '\Z');
212            while ($tabledata = $r->fetchRow(MDB2_FETCHMODE_ASSOC)) {
213                $dbdata .= sprintf("INSERT INTO `%s` VALUES (", $table);
214                $values = array();
215                foreach ($tabledata as $k=>$v) {
216                    if (array_key_exists($k, $ints))
217                        $values[] = $v;
218                    else
219                        $values[] = "'".str_replace($search, $replace, $this->sql_addslashes($v))."'";
220                }
221                $dbdata .= implode(",", $values);
222                $dbdata .= ");\n";
223            }
224            $dbdata .= sprintf("/*!40000 ALTER TABLE `%s` ENABLE KEYS */;\n", $table);
225            $dbdata .= "UNLOCK TABLES;\n\n";
226        }
227        $dbdata .= "/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n\n";
228        $dbdata .= "/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n";
229        $dbdata .= "/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n";
230        $dbdata .= "/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n";
231        $dbdata .= "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n";
232        $dbdata .= "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n";
233        $dbdata .= "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n";
234        $dbdata .= "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n\n";
235        $dbdata .= sprintf("-- Dump completed on %s", date("Y-m-d H:i:s"));
236
237        $backupfile = sprintf($backuplocation."%s-%s.mysql", $database, date("YmdHi"));
238        return file_put_contents($backupfile, $dbdata);
239    }
240    /* }}} */
241    /* _psql_backup_db {{{ */
242    /**
243     * Create postgresql backup. Code and ideas borrowed from phpPgAdmin.
244     *
245     * @param string $database The database name to backup
246     * @param string $backuplocation The directory to store the backup in
247     * @return bool true on success, false on failure
248     */
249    private function _psql_backup_db($database, $backuplocation) {
250        // set enviroment vars needed by pg_dump
251        $server_info = array();
252        $server_info["username"] = $this->db->dsn["username"];
253        $server_info["password"] = $this->db->dsn["password"];
254        $server_info["host"]     = $this->db->dsn["hostspec"];
255        $server_info["port"]     = $this->db->dsn["port"];
256
257        putenv('PGPASSWORD=' . $server_info['password']);
258        putenv('PGUSER=' . $server_info['username']);
259        $hostname = $server_info['host'];
260        if ($hostname !== null && $hostname != '') {
261            putenv('PGHOST=' . $hostname);
262        }
263        $port = $server_info['port'];
264        if ($port !== null && $port != '') {
265            putenv('PGPORT=' . $port);
266        }
267
268        $backupfile = sprintf($backuplocation."%s-%s.psql", $database, date("YmdHi"));
269        $cmd = "pg_dump -i ";
270        $cmd .= sprintf("-f %s %s", $backupfile, $database);
271        $output = system($cmd, $retval);
272        if ($retval === 0)
273            return true;
274        else
275            return false;
276    }
277    /* }}} */
278    /* set_latest_version {{{ */
279    /**
280     * Update/create dbversion setting in the database
281     *
282     * @param int $version The latest patchlevel we applied to the database
283     */
284    public function set_latest_version($version=0) {
285        if (array_key_exists("dbversion", $this->settings) && $this->settings["dbversion"]) {
286            /* update the entry */
287            $sql = sprintf("UPDATE settings SET settingvalue = '%s' WHERE settingname = 'dbversion'", $version);
288        } else {
289            /* create the entry */
290            $sql = sprintf("INSERT INTO settings (settingname, settingvalue) VALUES ('dbversion', '%s')", $version);
291        }
292        $res = $this->db->exec($sql);
293        if (PEAR::isError($res))
294            return false;
295        else
296            return true;
297    }
298    /* }}} */
299    /* apply_dbpatch {{{ */
300    /**
301     * Apply a specific database patch
302     *
303     * @param int $patch The patch to apply
304     */
305    public function apply_dbpatch($patch, $mode = "release") {
306        $patchfile = sprintf("upgrades/%s/%s", $this->db->phptype, $patch);
307        if (file_exists($patchfile)) {
308            require_once($patchfile);
309            foreach ($sql as $query) {
310                $res = $this->db->exec($query);
311                if (PEAR::isError($res))
312                    return false;
313            }
314        }
315        if ($mode == "release")
316            $this->lastpatch = substr(basename($patch, ".php"), strpos($patch, "to")+2);
317        else
318            $this->lastpatch = basename($patch, ".php");
319        return true;
320    }
321    /* }}} */
322}
323?>
Note: See TracBrowser for help on using the browser.