1#!/usr/bin/env php 2<?php 3 4echo "SabreDAV migrate script for version 2.1\n"; 5 6if ($argc<2) { 7 8 echo <<<HELLO 9 10This script help you migrate from a pre-2.1 database to 2.1. 11 12Changes: 13 The 'calendarobjects' table will be upgraded. 14 'schedulingobjects' will be created. 15 16If you don't use the default PDO CalDAV or CardDAV backend, it's pointless to 17run this script. 18 19Keep in mind that ALTER TABLE commands will be executed. If you have a large 20dataset this may mean that this process takes a while. 21 22Lastly: Make a back-up first. This script has been tested, but the amount of 23potential variants are extremely high, so it's impossible to deal with every 24possible situation. 25 26In the worst case, you will lose all your data. This is not an overstatement. 27 28Usage: 29 30php {$argv[0]} [pdo-dsn] [username] [password] 31 32For example: 33 34php {$argv[0]} "mysql:host=localhost;dbname=sabredav" root password 35php {$argv[0]} sqlite:data/sabredav.db 36 37HELLO; 38 39 exit(); 40 41} 42 43// There's a bunch of places where the autoloader could be, so we'll try all of 44// them. 45$paths = [ 46 __DIR__ . '/../vendor/autoload.php', 47 __DIR__ . '/../../../autoload.php', 48]; 49 50foreach($paths as $path) { 51 if (file_exists($path)) { 52 include $path; 53 break; 54 } 55} 56 57$dsn = $argv[1]; 58$user = isset($argv[2])?$argv[2]:null; 59$pass = isset($argv[3])?$argv[3]:null; 60 61echo "Connecting to database: " . $dsn . "\n"; 62 63$pdo = new PDO($dsn, $user, $pass); 64$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 65$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 66 67$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME); 68 69switch($driver) { 70 71 case 'mysql' : 72 echo "Detected MySQL.\n"; 73 break; 74 case 'sqlite' : 75 echo "Detected SQLite.\n"; 76 break; 77 default : 78 echo "Error: unsupported driver: " . $driver . "\n"; 79 die(-1); 80} 81 82echo "Upgrading 'calendarobjects'\n"; 83$addUid = false; 84try { 85 $result = $pdo->query('SELECT * FROM calendarobjects LIMIT 1'); 86 $row = $result->fetch(\PDO::FETCH_ASSOC); 87 88 if (!$row) { 89 echo "No data in table. Going to try to add the uid field anyway.\n"; 90 $addUid = true; 91 } elseif (array_key_exists('uid', $row)) { 92 echo "uid field exists. Assuming that this part of the migration has\n"; 93 echo "Already been completed.\n"; 94 } else { 95 echo "2.0 schema detected.\n"; 96 $addUid = true; 97 } 98 99} catch (Exception $e) { 100 echo "Could not find a calendarobjects table. Skipping this part of the\n"; 101 echo "upgrade.\n"; 102} 103 104if ($addUid) { 105 106 switch($driver) { 107 case 'mysql' : 108 $pdo->exec('ALTER TABLE calendarobjects ADD uid VARCHAR(200)'); 109 break; 110 case 'sqlite' : 111 $pdo->exec('ALTER TABLE calendarobjects ADD uid TEXT'); 112 break; 113 } 114 115 $result = $pdo->query('SELECT id, calendardata FROM calendarobjects'); 116 $stmt = $pdo->prepare('UPDATE calendarobjects SET uid = ? WHERE id = ?'); 117 $counter = 0; 118 119 while($row = $result->fetch(\PDO::FETCH_ASSOC)) { 120 121 try { 122 $vobj = \Sabre\VObject\Reader::read($row['calendardata']); 123 } catch (\Exception $e) { 124 echo "Warning! Item with id $row[id] could not be parsed!\n"; 125 continue; 126 } 127 $uid = null; 128 $item = $vobj->getBaseComponent(); 129 if (!isset($item->UID)) { 130 echo "Warning! Item with id $item[id] does NOT have a UID property and this is required.\n"; 131 continue; 132 } 133 $uid = (string)$item->UID; 134 $stmt->execute([$uid, $row['id']]); 135 $counter++; 136 137 } 138 139} 140 141echo "Creating 'schedulingobjects'\n"; 142 143switch($driver) { 144 145 case 'mysql' : 146 $pdo->exec('CREATE TABLE IF NOT EXISTS schedulingobjects 147( 148 id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 149 principaluri VARCHAR(255), 150 calendardata MEDIUMBLOB, 151 uri VARCHAR(200), 152 lastmodified INT(11) UNSIGNED, 153 etag VARCHAR(32), 154 size INT(11) UNSIGNED NOT NULL 155) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 156 '); 157 break; 158 159 160 case 'sqlite' : 161 $pdo->exec('CREATE TABLE IF NOT EXISTS schedulingobjects ( 162 id integer primary key asc, 163 principaluri text, 164 calendardata blob, 165 uri text, 166 lastmodified integer, 167 etag text, 168 size integer 169) 170'); 171 break; 172 $pdo->exec(' 173 CREATE INDEX principaluri_uri ON calendarsubscriptions (principaluri, uri); 174 '); 175 break; 176} 177 178echo "Done.\n"; 179 180echo "Upgrade to 2.1 schema completed.\n"; 181