insert/update timezones without sqlite extension

This commit is contained in:
Ralf Becker 2014-10-07 21:05:39 +00:00
parent 80f33c47a8
commit f72d66c17c
5 changed files with 243 additions and 354 deletions

View File

@ -84,7 +84,7 @@ class calendar_timezones
* - calendar_timezone::tz2id('Europe/Berlin','component') returns VTIMEZONE component for given TZID
*
* @param string $tzid TZID
* @param string $what='id' what to return, default id, null for whole array
* @param string $what ='id' what to return, default id, null for whole array
* @return int tz_id or null if not found
*/
public static function tz2id($tzid,$what='id')
@ -105,7 +105,7 @@ class calendar_timezones
if (!isset($id) && stripos($tzid, 'America/') === 0 && count($parts = explode('/', $tzid)) == 2)
{
if (($data = $GLOBALS['egw']->db->select(self::TABLE,'*',array(
'tz_tzid LIKE '.$GLOBALS['egw']->db->quote($parts[0].'/%/'.$part[1]),
'tz_tzid LIKE '.$GLOBALS['egw']->db->quote($parts[0].'/%/'.$parts[1]),
),__LINE__,__FILE__,false,'','calendar')->fetch()))
{
$id = $data['tz_id'];
@ -129,7 +129,7 @@ class calendar_timezones
* - calendar_timezone::id2tz($id,'component') returns VTIMEZONE component for the given id
*
* @param int $id
* @param string $what='tzid' what data to return or null for whole data array, with keys 'id', 'tzid', 'component', 'alias', 'latitude', 'longitude'
* @param string $what ='tzid' what data to return or null for whole data array, with keys 'id', 'tzid', 'component', 'alias', 'latitude', 'longitude'
* @return mixed false: if not found
*/
public static function id2tz($id,$what='tzid')
@ -177,17 +177,21 @@ class calendar_timezones
// check for updated timezones once per session
if (!egw_cache::getSession(__CLASS__, 'tzs_checked'))
{
$updated = false;
try
{
$msg = self::import_sqlite($updated);
if ($updated) error_log($msg); // log that timezones have been updated
$msg = self::import_tz_aliases($updated);
if ($updated) error_log($msg); // log that timezone aliases have been updated
}
catch (Exception $e)
catch (egw_exception_wrong_userinput $e)
{
_egw_log_exception($e); // log the exception to error_log, but do not stall program execution
unset($e);
$msg = self::import_db_backup($updated);
if ($updated) error_log($msg); // log that timezones have been updated
}
$alias_msg = self::import_tz_aliases($updated);
if ($updated) error_log($alias_msg); // log that timezone aliases have been updated
egw_cache::setSession(__CLASS__, 'tzs_checked', true);
}
}
@ -196,10 +200,10 @@ class calendar_timezones
* Import timezones from sqlite file
*
* @param boolean &$updated=null on return true if update was neccessary, false if tz's were already up to date
* @param string $file='calendar/setup/timezones.sqlite' filename relative to EGW_SERVER_ROOT
* @param string $file ='calendar/setup/timezones.sqlite' filename relative to EGW_SERVER_ROOT
* @return string message about update
* @throws egw_exception_wrong_parameter if $file is not readable or wrong format/version
* @throws egw_exception_assertion_failed if no PDO sqlite support
* @throws egw_exception_wrong_userinput if no PDO sqlite support
* @throws egw_exception_wrong_userinput for broken sqlite extension
*/
public static function import_sqlite(&$updated=null, $file='calendar/setup/timezones.sqlite')
@ -271,15 +275,46 @@ class calendar_timezones
}
/**
* Import timezone aliases
* Import timezone via db_backup of egw_cal_timezones
*
* @param boolean &$updated=null on return true if update was neccessary, false if tz's were already up to date
* @param string $file='calendar/setup/tz_aliases.inc.php' filename relative to EGW_SERVER_ROOT
* @param boolean $check_mtime=true true: check version and only act, if it's different
* @param string $file ='calendar/setup/tz_aliases.inc.php' filename relative to EGW_SERVER_ROOT
* @return string message about update
* @throws egw_exception_wrong_parameter if $file is not readable or wrong format/version
*/
public static function import_tz_aliases(&$updated=null,$file='calendar/setup/tz_aliases.inc.php',$check_mtime=true)
public static function import_db_backup(&$updated=null,$file='calendar/setup/timezones.db_backup')
{
$path = EGW_SERVER_ROOT.'/'.$file;
if (!file_exists($path) || !is_readable($path))
{
throw new egw_exception_wrong_parameter(__METHOD__."('$file') not found or readable!");
}
$config = config::read('phpgwapi');
$tz_version = date('Y-m-d H:i:s', filemtime($path));
if ($tz_version === $config['tz_version'])
{
$updated = false;
return lang('Nothing to update, version is already %1.',$tz_version);
}
$db_backup = new db_backup();
$rows = $db_backup->db_restore($db_backup->fopen_backup($path, true), 'tz_tzid');
config::save_value('tz_version', $tz_version, 'phpgwapi');
$updated = true;
return lang('Timezones updated to version %1 (%2 records updated).', $tz_version, $rows-8); // -8 because of header-lines
}
/**
* Import timezone aliases
*
* @param boolean &$updated=null on return true if update was neccessary, false if tz's were already up to date
* @param string $file ='calendar/setup/tz_aliases.inc.php' filename relative to EGW_SERVER_ROOT
* @return string message about update
* @throws egw_exception_wrong_parameter if $file is not readable or wrong format/version
*/
public static function import_tz_aliases(&$updated=null,$file='calendar/setup/tz_aliases.inc.php')
{
$path = EGW_SERVER_ROOT.'/'.$file;
@ -294,6 +329,7 @@ class calendar_timezones
$updated = false;
return lang('Nothing to update, version is already %1.',$tz_aliases_mtime);
}
$tz_aliases = array();
include($path); // sets $tz_aliases
$updates = 0;
@ -328,10 +364,17 @@ class calendar_timezones
{
throw new egw_exception_no_permission_admin();
}
$GLOBALS['egw']->framework->render(
'<h3>'.self::import_sqlite()."</h3>\n".
'<h3>'.self::import_tz_aliases()."</h3>\n",
lang('Update timezones'),true);
try {
$output = '<h3>'.self::import_sqlite()."</h3>\n";
}
catch (egw_exception_wrong_userinput $e)
{
unset($e);
$output = '<h3>'.self::import_db_backup()."</h3>\n";
}
$output .= '<h3>'.self::import_tz_aliases()."</h3>\n";
$GLOBALS['egw']->framework->render($output, lang('Update timezones'), true);
}
/**
@ -347,7 +390,7 @@ class calendar_timezones
// checking type of $val, now we included the object definition (no need to always include it!)
if (!$vcal instanceof Horde_iCalendar)
{
throw new egw_exception_wrong_parameter(__METHOD__.'('.array2string($val).", '$tzid') no Horde_iCalendar!");
throw new egw_exception_wrong_parameter(__METHOD__.'('.array2string($vcal).", '$tzid') no Horde_iCalendar!");
}
// check if we have vtimezone component data for $tzid
if (!($vtimezone = calendar_timezones::tz2id($tzid, 'component')))
@ -362,16 +405,16 @@ class calendar_timezones
$standard = $horde_vtimezone->findComponent('STANDARD');
if (is_a($standard, 'Horde_iCalendar'))
{
$dtstart = $standard->getAttribute('DTSTART');
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
$time = $standard->getAttribute('DTSTART');
$dtstart = new egw_time($time, egw_time::$server_timezone);
$dtstart->setTimezone(egw_time::$server_timezone);
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
}
$daylight = $horde_vtimezone->findComponent('DAYLIGHT');
if (is_a($daylight, 'Horde_iCalendar'))
{
$dtstart = $daylight->getAttribute('DTSTART');
$dtstart = new egw_time($dtstart, egw_time::$server_timezone);
$time = $daylight->getAttribute('DTSTART');
$dtstart = new egw_time($time, egw_time::$server_timezone);
$dtstart->setTimezone(egw_time::$server_timezone);
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
}
@ -384,8 +427,8 @@ class calendar_timezones
/**
* Query timezone of a given user, returns 'tzid' or VTIMEZONE 'component'
*
* @param int $user=null
* @param string $type='vcalendar' 'tzid' or everything tz2id supports, default 'vcalendar' = full vcalendar component
* @param int $user =null
* @param string $type ='vcalendar' 'tzid' or everything tz2id supports, default 'vcalendar' = full vcalendar component
* @return string
*/
public static function user_timezone($user=null, $type='vcalendar')

View File

@ -27,11 +27,10 @@ foreach(array(
try
{
calendar_timezones::import_sqlite();
calendar_timezones::import_tz_aliases();
}
// catch missing or broken sqlite support and use timezones.db_backup to install timezones
catch (egw_exception_wrong_userinput $e) // all other exceptions are fatal
{
$db_backup = new db_backup();
$db_backup->restore($db_backup->fopen_backup(EGW_SERVER_ROOT.'/calendar/setup/timezones.db_backup', true), true, '', false);
}
calendar_timezones::import_db_backup();
}
calendar_timezones::import_tz_aliases();

View File

@ -439,179 +439,3 @@ tz_id,tz_tzid,tz_alias,tz_latitude,tz_longitude,tz_component
431,"Europe/Belfast",338,NULL,NULL,NULL
432,"Atlantic/Jan_Mayen",347,NULL,NULL,NULL
433,"Pacific/Yap",421,NULL,NULL,NULL
434,"AUS Central Standard Time",307,NULL,NULL,NULL
435,"AUS Eastern Standard Time",314,NULL,NULL,NULL
436,"Afghanistan Standard Time",246,NULL,NULL,NULL
437,"Alaskan Standard Time",54,NULL,NULL,NULL
438,"Arab Standard Time",273,NULL,NULL,NULL
439,"Arabian Standard Time",233,NULL,NULL,NULL
440,"Arabic Standard Time",220,NULL,NULL,NULL
441,"Argentina Standard Time",58,NULL,NULL,NULL
442,"Atlantic Standard Time",113,NULL,NULL,NULL
443,"Azerbaijan Standard Time",222,NULL,NULL,NULL
444,"Azores Standard Time",293,NULL,NULL,NULL
445,"Bahia Standard Time",73,NULL,NULL,NULL
446,"Bangladesh Standard Time",231,NULL,NULL,NULL
447,"Canada Central Standard Time",172,NULL,NULL,NULL
448,"Cape Verde Standard Time",296,NULL,NULL,NULL
449,"Caucasus Standard Time",292,NULL,NULL,NULL
450,"Cen. Australia Standard Time",303,NULL,NULL,NULL
451,"Central America Standard Time",110,NULL,NULL,NULL
452,"Central Asia Standard Time",214,NULL,NULL,NULL
453,"Central Brazilian Standard Time",92,NULL,NULL,NULL
454,"Central Europe Standard Time",323,NULL,NULL,NULL
455,"Central European Standard Time",368,NULL,NULL,NULL
456,"Central Pacific Standard Time",395,NULL,NULL,NULL
457,"Central Standard Time",88,NULL,NULL,NULL
458,"Central Standard Time (Mexico)",145,NULL,NULL,NULL
459,"China Standard Time",277,NULL,NULL,NULL
460,"E. Africa Standard Time",43,NULL,NULL,NULL
461,"E. Australia Standard Time",304,NULL,NULL,NULL
462,"E. Europe Standard Time",262,NULL,NULL,NULL
463,"E. South America Standard Time",179,NULL,NULL,NULL
464,"Eastern Standard Time",153,NULL,NULL,NULL
465,"Egypt Standard Time",13,NULL,NULL,NULL
466,"Ekaterinburg Standard Time",291,NULL,NULL,NULL
467,"FLE Standard Time",335,NULL,NULL,NULL
468,"Fiji Standard Time",391,NULL,NULL,NULL
469,"GMT Standard Time",338,NULL,NULL,NULL
470,"GTB Standard Time",322,NULL,NULL,NULL
471,"Georgian Standard Time",281,NULL,NULL,NULL
472,"Greenland Standard Time",105,NULL,NULL,NULL
473,"Greenwich Standard Time",299,NULL,NULL,NULL
474,"Hawaiian Standard Time",397,NULL,NULL,NULL
475,"India Standard Time",252,NULL,NULL,NULL
476,"Iran Standard Time",282,NULL,NULL,NULL
477,"Israel Standard Time",245,NULL,NULL,NULL
478,"Jordan Standard Time",215,NULL,NULL,NULL
479,"Kaliningrad Standard Time",334,NULL,NULL,NULL
480,"Korea Standard Time",276,NULL,NULL,NULL
481,"Magadan Standard Time",258,NULL,NULL,NULL
482,"Mauritius Standard Time",380,NULL,NULL,NULL
483,"Middle East Standard Time",224,NULL,NULL,NULL
484,"Montevideo Standard Time",149,NULL,NULL,NULL
485,"Morocco Standard Time",14,NULL,NULL,NULL
486,"Mountain Standard Time",97,NULL,NULL,NULL
487,"Mountain Standard Time (Mexico)",89,NULL,NULL,NULL
488,"Myanmar Standard Time",272,NULL,NULL,NULL
489,"N. Central Asia Standard Time",264,NULL,NULL,NULL
490,"Namibia Standard Time",52,NULL,NULL,NULL
491,"Nepal Standard Time",250,NULL,NULL,NULL
492,"New Zealand Standard Time",384,NULL,NULL,NULL
493,"Newfoundland Standard Time",184,NULL,NULL,NULL
494,"North Asia East Standard Time",241,NULL,NULL,NULL
495,"North Asia Standard Time",253,NULL,NULL,NULL
496,"Pacific SA Standard Time",177,NULL,NULL,NULL
497,"Pacific Standard Time",133,NULL,NULL,NULL
498,"Pacific Standard Time (Mexico)",175,NULL,NULL,NULL
499,"Pakistan Standard Time",248,NULL,NULL,NULL
500,"Paraguay Standard Time",71,NULL,NULL,NULL
501,"Romance Standard Time",348,NULL,NULL,NULL
502,"Russian Standard Time",345,NULL,NULL,NULL
503,"SA Eastern Standard Time",86,NULL,NULL,NULL
504,"SA Pacific Standard Time",80,NULL,NULL,NULL
505,"SA Western Standard Time",131,NULL,NULL,NULL
506,"SE Asia Standard Time",223,NULL,NULL,NULL
507,"Samoa Standard Time",383,NULL,NULL,NULL
508,"Singapore Standard Time",278,NULL,NULL,NULL
509,"South Africa Standard Time",25,NULL,NULL,NULL
510,"Sri Lanka Standard Time",229,NULL,NULL,NULL
511,"Syria Standard Time",230,NULL,NULL,NULL
512,"Taipei Standard Time",279,NULL,NULL,NULL
513,"Tasmania Standard Time",309,NULL,NULL,NULL
514,"Tokyo Standard Time",284,NULL,NULL,NULL
515,"Tonga Standard Time",418,NULL,NULL,NULL
516,"Turkey Standard Time",332,NULL,NULL,NULL
517,"US Mountain Standard Time",164,NULL,NULL,NULL
518,"Ulaanbaatar Standard Time",285,NULL,NULL,NULL
519,"Venezuela Standard Time",85,NULL,NULL,NULL
520,"Vladivostok Standard Time",289,NULL,NULL,NULL
521,"W. Australia Standard Time",313,NULL,NULL,NULL
522,"W. Central Africa Standard Time",31,NULL,NULL,NULL
523,"W. Europe Standard Time",319,NULL,NULL,NULL
524,"West Asia Standard Time",280,NULL,NULL,NULL
525,"West Pacific Standard Time",413,NULL,NULL,NULL
526,"Yakutsk Standard Time",290,NULL,NULL,NULL
527,"Universal Coordinated Time",-1,NULL,NULL,NULL
528,"Casablanca, Monrovia",14,NULL,NULL,NULL
529,"Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London",336,NULL,NULL,NULL
530,"Greenwich Mean Time; Dublin, Edinburgh, London",338,NULL,NULL,NULL
531,"Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna",319,NULL,NULL,NULL
532,"Belgrade, Pozsony, Budapest, Ljubljana, Prague",350,NULL,NULL,NULL
533,"Brussels, Copenhagen, Madrid, Paris",348,NULL,NULL,NULL
534,"Paris, Madrid, Brussels, Copenhagen",348,NULL,NULL,NULL
535,"Prague, Central Europe",350,NULL,NULL,NULL
536,"Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb",355,NULL,NULL,NULL
537,"West Central Africa",34,NULL,NULL,NULL
538,"Athens, Istanbul, Minsk",317,NULL,NULL,NULL
539,"Bucharest",322,NULL,NULL,NULL
540,"Cairo",13,NULL,NULL,NULL
541,"Harare, Pretoria",24,NULL,NULL,NULL
542,"Helsinki, Riga, Tallinn",330,NULL,NULL,NULL
543,"Israel, Jerusalem Standard Time",245,NULL,NULL,NULL
544,"Baghdad",220,NULL,NULL,NULL
545,"Arab, Kuwait, Riyadh",256,NULL,NULL,NULL
546,"Moscow, St. Petersburg, Volgograd",345,NULL,NULL,NULL
547,"East Africa, Nairobi",43,NULL,NULL,NULL
548,"Tehran",282,NULL,NULL,NULL
549,"Abu Dhabi, Muscat",261,NULL,NULL,NULL
550,"Baku, Tbilisi, Yerevan",222,NULL,NULL,NULL
551,"Kabul",246,NULL,NULL,NULL
552,"Ekaterinburg",291,NULL,NULL,NULL
553,"Islamabad, Karachi, Tashkent",248,NULL,NULL,NULL
554,"Kolkata, Chennai, Mumbai, New Delhi, India Standard Time",429,NULL,NULL,NULL
555,"Kathmandu, Nepal",250,NULL,NULL,NULL
556,"Almaty, Novosibirsk, North Central Asia",214,NULL,NULL,NULL
557,"Astana, Dhaka",231,NULL,NULL,NULL
558,"Sri Jayawardenepura, Sri Lanka",229,NULL,NULL,NULL
559,"Rangoon",272,NULL,NULL,NULL
560,"Bangkok, Hanoi, Jakarta",223,NULL,NULL,NULL
561,"Krasnoyarsk",253,NULL,NULL,NULL
562,"Beijing, Chongqing, Hong Kong SAR, Urumqi",277,NULL,NULL,NULL
563,"Irkutsk, Ulaan Bataar",241,NULL,NULL,NULL
564,"Kuala Lumpur, Singapore",278,NULL,NULL,NULL
565,"Perth, Western Australia",313,NULL,NULL,NULL
566,"Taipei",279,NULL,NULL,NULL
567,"Osaka, Sapporo, Tokyo",284,NULL,NULL,NULL
568,"Seoul, Korea Standard time",276,NULL,NULL,NULL
569,"Yakutsk",290,NULL,NULL,NULL
570,"Adelaide, Central Australia",303,NULL,NULL,NULL
571,"Darwin",307,NULL,NULL,NULL
572,"Brisbane, East Australia",304,NULL,NULL,NULL
573,"Canberra, Melbourne, Sydney, Hobart (year 2000 only)",314,NULL,NULL,NULL
574,"Guam, Port Moresby",396,NULL,NULL,NULL
575,"Hobart, Tasmania",309,NULL,NULL,NULL
576,"Vladivostok",289,NULL,NULL,NULL
577,"Magadan, Solomon Is., New Caledonia",258,NULL,NULL,NULL
578,"Auckland, Wellington",384,NULL,NULL,NULL
579,"Fiji Islands, Kamchatka, Marshall Is.",391,NULL,NULL,NULL
580,"Nuku'alofa, Tonga",418,NULL,NULL,NULL
581,"Azores",293,NULL,NULL,NULL
582,"Cape Verde Is.",296,NULL,NULL,NULL
583,"Mid-Atlantic",156,NULL,NULL,NULL
584,"Brasilia",179,NULL,NULL,NULL
585,"Buenos Aires",58,NULL,NULL,NULL
586,"Greenland",105,NULL,NULL,NULL
587,"Newfoundland",184,NULL,NULL,NULL
588,"Atlantic Time (Canada)",113,NULL,NULL,NULL
589,"Caracas, La Paz",85,NULL,NULL,NULL
590,"Santiago",177,NULL,NULL,NULL
591,"Bogota, Lima, Quito",80,NULL,NULL,NULL
592,"Eastern Time (US & Canada)",153,NULL,NULL,NULL
593,"Indiana (East)",116,NULL,NULL,NULL
594,"Central America",110,NULL,NULL,NULL
595,"Central Time (US & Canada)",88,NULL,NULL,NULL
596,"Mexico City, Tegucigalpa",145,NULL,NULL,NULL
597,"Saskatchewan",100,NULL,NULL,NULL
598,"Arizona",164,NULL,NULL,NULL
599,"Mountain Time (US & Canada)",97,NULL,NULL,NULL
600,"Pacific Time (US & Canada); Tijuana",133,NULL,NULL,NULL
601,"Alaska",54,NULL,NULL,NULL
602,"Hawaii",397,NULL,NULL,NULL
603,"Midway Island, Samoa",404,NULL,NULL,NULL
604,"Eniwetok, Kwajalein, Dateline Time",401,NULL,NULL,NULL
605,"Armenian Standard Time",292,NULL,NULL,NULL
606,"Mexico Standard Time",145,NULL,NULL,NULL
607,"Mexico Standard Time 2",89,NULL,NULL,NULL
608,"Mid-Atlantic Standard Time",300,NULL,NULL,NULL
609,"US/Eastern",153,NULL,NULL,NULL

View File

@ -416,155 +416,7 @@ class db_backup
$backup_db_halt_on_error = $this->db->Halt_On_Error;
$this->db->Halt_On_Error = 'no';
}
$table = False;
$n = 0;
$rows = array();
while(!feof($f))
{
$line = trim(fgets($f)); ++$n;
if (empty($line)) continue;
if (substr($line,0,9) == 'version: ')
{
$api_version = trim(substr($line,9));
continue;
}
if (substr($line,0,9) == 'charset: ')
{
$charset = trim(substr($line,9));
// needed if mbstring.func_overload > 0, else eg. substr does not work with non ascii chars
@ini_set('mbstring.internal_encoding',$charset);
// check if we really need to convert the charset, as it's not perfect and can do some damage
if ($convert_to_system_charset && !strcasecmp($this->schema_proc->system_charset, $charset))
{
$convert_to_system_charset = false; // no conversation necessary
}
// set the DB's client encoding (for mysql only if api_version >= 1.0.1.019)
if ((!$convert_to_system_charset || $this->db->capabilities['client_encoding']) &&
(substr($this->db->Type,0,5) != 'mysql' || !is_object($GLOBALS['egw_setup']) ||
$api_version && !$GLOBALS['egw_setup']->alessthanb($api_version,'1.0.1.019')))
{
$this->db->Link_ID->SetCharSet($charset);
if (!$convert_to_system_charset)
{
$this->schema_proc->system_charset = $charset; // so schema_proc uses it for the creation of the tables
}
}
continue;
}
if (substr($line,0,8) == 'schema: ')
{
// create the tables in the backup set
$this->schemas = json_php_unserialize(trim(substr($line,8)));
foreach($this->schemas as $table_name => $schema)
{
// if column is longtext in current schema, convert text to longtext, in case user already updated column
foreach($schema['fd'] as $col => &$def)
{
if ($def['type'] == 'text' && $this->db->get_column_attribute($col, $table_name, true, 'type') == 'longtext')
{
$def['type'] = 'longtext';
}
}
//echo "<pre>$table_name => ".self::write_array($schema,1)."</pre>\n";
$this->schema_proc->CreateTable($table_name, $schema);
}
continue;
}
if (substr($line,0,7) == 'table: ')
{
if ($rows) // flush pending rows of last table
{
$this->db->insert($table,$rows,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
$rows = array();
$table = substr($line,7);
if (!isset($this->schemas[$table])) $this->schemas[$table] = $this->db->get_table_definitions(true, $table);
$cols = self::csv_split($line=fgets($f)); ++$n;
$blobs = array();
foreach($this->schemas[$table]['fd'] as $col => $data)
{
if ($data['type'] == 'blob') $blobs[] = $col;
}
if (feof($f)) break;
continue;
}
if ($convert_to_system_charset && !$this->db->capabilities['client_encoding'])
{
if ($GLOBALS['egw_setup'])
{
if (!is_object($GLOBALS['egw_setup']->translation->sql))
{
$GLOBALS['egw_setup']->translation->setup_translation_sql();
}
}
}
if ($table) // do we already reached the data part
{
$import = true;
$data = self::csv_split($line, $cols, $blobs);
if ($table == 'egw_async' && in_array('##last-check-run##',$data))
{
//echo '<p>'.lang("Line %1: '%2'<br><b>csv data does contain ##last-check-run## of table %3 ==> ignored</b>",$n,$line,$table)."</p>\n";
//echo 'data=<pre>'.print_r($data,true)."</pre>\n";
$import = false;
}
if (in_array($table,$this->exclude_tables))
{
echo '<p><b>'.lang("Table %1 is excluded from backup and restore. Data will not be restored.",$table)."</b></p>\n";
$import = false; // dont restore data of excluded tables
}
if ($import)
{
if (count($data) == count($cols))
{
if ($convert_to_system_charset && !$this->db->capabilities['client_encoding'])
{
$data = translation::convert($data,$charset);
}
if ($insert_n_rows > 1)
{
$rows[] = $data;
if (count($rows) == $insert_n_rows)
{
$this->db->insert($table,$rows,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
$rows = array();
}
}
else
{
$this->db->insert($table,$data,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
}
else
{
echo '<p>'.lang("Line %1: '%2'<br><b>csv data does not match column-count of table %3 ==> ignored</b>",$n,$line,$table)."</p>\n";
echo 'data=<pre>'.print_r($data,true)."</pre>\n";
}
}
}
}
if ($rows) // flush pending rows
{
$this->db->insert($table,$rows,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
// updated the sequences, if the DB uses them
foreach($this->schemas as $table => $schema)
{
foreach($schema['fd'] as $column => $definition)
{
if ($definition['type'] == 'auto')
{
$this->schema_proc->UpdateSequence($table,$column);
break; // max. one per table
}
}
}
$this->db_restore($f, $insert_n_rows);
if ($convert_to_system_charset) // store the changed charset
{
@ -652,6 +504,177 @@ class db_backup
return '';
}
/**
* Restore data from a (compressed) csv file
*
* @param resource $f file opened with fopen for reading
* @param int|string $insert_n_rows =10 how many rows to insert in one sql statement, or string with column-name used as unique key for insert
* @returns int number of rows read from csv file
*/
function db_restore($f, $insert_n_rows=10)
{
$convert_to_system_charset = true;
$table = False;
$n = 0;
$rows = array();
while(!feof($f))
{
$line = trim(fgets($f)); ++$n;
if (empty($line)) continue;
if (substr($line,0,9) == 'version: ')
{
$api_version = trim(substr($line,9));
continue;
}
if (substr($line,0,9) == 'charset: ')
{
$charset = trim(substr($line,9));
// needed if mbstring.func_overload > 0, else eg. substr does not work with non ascii chars
@ini_set('mbstring.internal_encoding',$charset);
// check if we really need to convert the charset, as it's not perfect and can do some damage
if ($convert_to_system_charset && !strcasecmp($this->schema_proc->system_charset, $charset))
{
$convert_to_system_charset = false; // no conversation necessary
}
// set the DB's client encoding (for mysql only if api_version >= 1.0.1.019)
if ((!$convert_to_system_charset || $this->db->capabilities['client_encoding']) &&
(substr($this->db->Type,0,5) != 'mysql' || !is_object($GLOBALS['egw_setup']) ||
$api_version && !$GLOBALS['egw_setup']->alessthanb($api_version,'1.0.1.019')))
{
$this->db->Link_ID->SetCharSet($charset);
if (!$convert_to_system_charset)
{
$this->schema_proc->system_charset = $charset; // so schema_proc uses it for the creation of the tables
}
}
continue;
}
if (substr($line,0,8) == 'schema: ')
{
// create the tables in the backup set
$this->schemas = json_php_unserialize(trim(substr($line,8)));
foreach($this->schemas as $table_name => $schema)
{
// if column is longtext in current schema, convert text to longtext, in case user already updated column
foreach($schema['fd'] as $col => &$def)
{
if ($def['type'] == 'text' && $this->db->get_column_attribute($col, $table_name, true, 'type') == 'longtext')
{
$def['type'] = 'longtext';
}
}
//echo "<pre>$table_name => ".self::write_array($schema,1)."</pre>\n";
$this->schema_proc->CreateTable($table_name, $schema);
}
continue;
}
if (substr($line,0,7) == 'table: ')
{
if ($rows) // flush pending rows of last table
{
$this->db->insert($table,$rows,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
$rows = array();
$table = substr($line,7);
if (!isset($this->schemas[$table])) $this->schemas[$table] = $this->db->get_table_definitions(true, $table);
$auto_id = count($this->schemas[$table]['pk']) == 1 ? $this->schemas[$table]['pk'][0] : null;
$cols = self::csv_split($line=fgets($f)); ++$n;
$blobs = array();
foreach($this->schemas[$table]['fd'] as $col => $data)
{
if ($data['type'] == 'blob') $blobs[] = $col;
}
if (feof($f)) break;
continue;
}
if ($convert_to_system_charset && !$this->db->capabilities['client_encoding'])
{
if ($GLOBALS['egw_setup'])
{
if (!is_object($GLOBALS['egw_setup']->translation->sql))
{
$GLOBALS['egw_setup']->translation->setup_translation_sql();
}
}
}
if ($table) // do we already reached the data part
{
$import = true;
$data = self::csv_split($line, $cols, $blobs);
if ($table == 'egw_async' && in_array('##last-check-run##',$data))
{
//echo '<p>'.lang("Line %1: '%2'<br><b>csv data does contain ##last-check-run## of table %3 ==> ignored</b>",$n,$line,$table)."</p>\n";
//echo 'data=<pre>'.print_r($data,true)."</pre>\n";
$import = false;
}
if (in_array($table,$this->exclude_tables))
{
echo '<p><b>'.lang("Table %1 is excluded from backup and restore. Data will not be restored.",$table)."</b></p>\n";
$import = false; // dont restore data of excluded tables
}
if ($import)
{
if (count($data) == count($cols))
{
if ($convert_to_system_charset && !$this->db->capabilities['client_encoding'])
{
$data = translation::convert($data,$charset);
}
if ($insert_n_rows > 1)
{
$rows[] = $data;
if (count($rows) == $insert_n_rows)
{
$this->db->insert($table,$rows,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
$rows = array();
}
}
// update existing table using given unique key in $insert_n_rows (also removing auto-id/sequence)
elseif(!is_numeric($insert_n_rows))
{
$where = array($insert_n_rows => $data[$insert_n_rows]);
unset($data[$insert_n_rows]);
if ($auto_id) unset($data[$auto_id]);
$this->db->insert($table,$data,$where,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
else
{
$this->db->insert($table,$data,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
}
else
{
echo '<p>'.lang("Line %1: '%2'<br><b>csv data does not match column-count of table %3 ==> ignored</b>",$n,$line,$table)."</p>\n";
echo 'data=<pre>'.print_r($data,true)."</pre>\n";
}
}
}
}
if ($rows) // flush pending rows
{
$this->db->insert($table,$rows,False,__LINE__,__FILE__,false,false,$this->schemas[$table]);
}
// updated the sequences, if the DB uses them
foreach($this->schemas as $table => $schema)
{
foreach($schema['fd'] as $column => $definition)
{
if ($definition['type'] == 'auto')
{
$this->schema_proc->UpdateSequence($table,$column);
break; // max. one per table
}
}
}
return $n;
}
/**
* Removes a dir, no matter whether it is empty or full
*

View File

@ -1750,7 +1750,7 @@ class egw_db
$this->select($table,'count(*)',$where,$line,$file);
if ($this->next_record() && $this->f(0))
{
return !!$this->update($table,$data,$where,$line,$file,$app);
return !!$this->update($table,$data,$where,$line,$file,$app,$use_prepared_statement,$table_def);
}
break;
}