ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilDBGenerator.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
29 {
30  protected string $target_encoding = 'UTF-8';
31  protected array $whitelist = array();
32  protected array $blacklist = array();
33  protected array $tables = array();
34  protected array $filter = array();
35  protected ilDBManager $manager;
36  protected ilDBReverse $reverse;
37  protected ilDBInterface $il_db;
39  protected array $allowed_attributes = [];
40  protected array $fields = [];
41 
45  public function __construct()
46  {
47  global $DIC;
48  $ilDB = $DIC->database();
49 
50  $this->manager = $ilDB->loadModule(ilDBConstants::MODULE_MANAGER);
51  $this->reverse = $ilDB->loadModule(ilDBConstants::MODULE_REVERSE);
52  $this->il_db = $ilDB;
53  $this->analyzer = new ilDBAnalyzer();
54  $this->allowed_attributes = $ilDB->getAllowedAttributes();
55  }
56 
61  public static function lookupAbstractedTables(): array
62  {
63  global $DIC;
64  $ilDB = $DIC->database();
65 
66  $query = "SELECT DISTINCT(table_name) FROM abstraction_progress ";
67  $res = $ilDB->query($query);
68  $names = array();
69  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
70  $names[] = $row->table_name;
71  }
72 
73  // tables that have been already created in an abstracted
74  // way or tables that have been renamed after being abstracted
75  // (see db_update script)
76  $abs_tables = array_merge($names, array(
77  'acc_access_key',
78  'acc_user_access_key',
79  'ldap_rg_mapping',
80  'page_anchor',
81  'qpl_question_orderinghorizontal',
82  'qpl_question_fileupload',
83  'chat_smilies',
84  'style_color',
85  'style_template_class',
86  'style_template',
87  'page_style_usage',
88  'style_setting',
89  'page_editor_settings',
90  'mep_data',
91  'license_data',
92  'loginname_history',
93  'mep_item',
94  'qpl_a_cloze',
95  'qpl_a_imagemap',
96  'qpl_a_matching',
97  'qpl_num_range',
98  'qpl_qst_cloze',
99  'qpl_qst_essay',
100  'qpl_qst_fileupload',
101  'qpl_qst_flash',
102  'qpl_qst_horder',
103  'qpl_qst_imagemap',
104  'qpl_qst_javaapplet',
105  'qpl_qst_matching',
106  'qpl_qst_mc',
107  'qpl_qst_numeric',
108  'qpl_qst_ordering',
109  'qpl_qst_sc',
110  'qpl_qst_textsubset',
111  'qpl_qst_type',
112  'qpl_sol_sug',
113  'udf_text',
114  'udf_clob',
115  'xmlnestedsettmp',
116  'cache_text',
117  'cache_clob',
118  'qpl_a_errortext',
119  'qpl_qst_errortext',
120  'tst_rnd_cpy',
121  'tst_rnd_qpl_title',
122  'qpl_a_mdef',
123  ));
124 
125  return $abs_tables;
126  }
127 
142  public function setTargetEncoding(string $a_encoding): void
143  {
144  $this->target_encoding = $a_encoding;
145  }
146 
147  public function getTargetEncoding(): string
148  {
149  return $this->target_encoding;
150  }
151 
157  public function setBlackList(array $a_blacklist): void
158  {
159  $this->blacklist = $a_blacklist;
160  }
161 
162  public function getBlackList(): array
163  {
164  return $this->blacklist;
165  }
166 
173  public function setWhiteList(array $a_whitelist): void
174  {
175  $this->whitelist = $a_whitelist;
176  }
177 
178  public function getWhiteList(): array
179  {
180  return $this->whitelist;
181  }
182 
183  public function setFilter(string $a_filter, string $a_value): void
184  {
185  $this->filter[$a_filter] = $a_value;
186  }
187 
191  public function getTables(): array
192  {
193  return $this->tables = $this->manager->listTables();
194  }
195 
199  public function checkProcessing(string $a_table): bool
200  {
201  // check black list
202  if (in_array($a_table, $this->blacklist, true)) {
203  return false;
204  }
205 
206  // check white list
207  if (count($this->whitelist) > 0 && !in_array($a_table, $this->whitelist, true)) {
208  return false;
209  }
210 
211  return true;
212  }
213 
217  protected function openFile(string $a_path)
218  {
219  $start = '';
220  $file = fopen($a_path, 'wb');
221  $start .= "\t" . 'global $ilDB;' . "\n\n";
222  fwrite($file, $start);
223 
224  return $file;
225  }
226 
230  protected function closeFile($fp): void
231  {
232  fclose($fp);
233  }
234 
239  public function buildDBGenerationScript(string $a_filename = ""): void
240  {
241  if (@is_dir($a_filename)) {
242  $is_dir = true;
243  $path = $a_filename;
244  } else {
245  $is_dir = false;
246  $path = '';
247  }
248 
249  $file = "";
250  if ($a_filename !== "" && !$is_dir) {
251  $file = fopen($a_filename, 'wb');
252 
253  $start = '<?php' . "\n" . 'function setupILIASDatabase()' . "\n{\n";
254  $start .= "\t" . 'global $ilDB;' . "\n\n";
255  fwrite($file, $start);
256  } else {
257  echo "<pre>";
258  }
259 
260  foreach ($this->getTables() as $table) {
261  if ($this->checkProcessing($table)) {
262  if ($a_filename !== "") {
263  flush();
264  }
265 
266  if ($is_dir) {
267  $file = $this->openFile($path . '/' . $table);
268  }
269 
270  // create table statement
271  $this->buildCreateTableStatement($table, $file);
272 
273  // primary key
274  $this->buildAddPrimaryKeyStatement($table, $file);
275 
276  // indices
277  $this->buildAddIndexStatements($table, $file);
278 
279  // constraints (currently unique keys)
280  $this->buildAddUniqueConstraintStatements($table, $file);
281 
282  // auto increment sequence
283  $this->buildCreateSequenceStatement($table, $file);
284 
285  if (in_array($table, array('usr_session_stats', 'usr_session_raw', 'il_plugin'))) {
286  continue;
287  }
288 
289  // inserts
290  if ($is_dir) {
291  $this->buildInsertStatement($table, $path);
292  #$this->buildInsertStatementsXML($table,$path);
293  } else {
294  $this->buildInsertStatements($table, $file);
295  }
296 
297  if ($is_dir) {
298  $this->closeFile($file);
299  }
300  } elseif ($a_filename !== "") {
301  echo "<br><b>missing: " . $table . "</b>";
302  flush();
303  }
304  }
305 
306  // sequence(s) without table (of same name)
307  $this->buildSingularSequenceStatement($file);
308 
309  if ($a_filename === "") {
310  echo "</pre>";
311  } elseif (!$is_dir) {
312  $end = "\n}\n?>\n";
313  $ok = fwrite($file, $end);
314  fclose($file);
315  }
316  }
317 
323  public function buildCreateTableStatement(string $a_table, $a_file = null): void
324  {
325  $fields = $this->analyzer->getFieldInformation($a_table, true);
326  $this->fields = $fields;
327  $create_st = "\n\n//\n// " . $a_table . "\n//\n";
328  $create_st .= '$fields = array (' . "\n";
329  $f_sep = "";
330  foreach ($fields as $f => $def) {
331  $create_st .= "\t" . $f_sep . '"' . $f . '" => array (' . "\n";
332  $f_sep = ",";
333  $a_sep = "";
334  foreach ($def as $k => $v) {
335  if ($k !== "nativetype" && $k !== "alt_types" && $k !== "autoincrement" && !is_null($v)) {
336  switch ($k) {
337  case "notnull":
338  case "unsigned":
339  case "fixed":
340  $v = $v ? "true" : "false";
341  break;
342 
343  case "default":
344  case "type":
345  $v = '"' . $v . '"';
346  break;
347 
348  default:
349  break;
350  }
351  $create_st .= "\t\t" . $a_sep . '"' . $k . '" => ' . $v . "\n";
352  $a_sep = ",";
353  }
354  }
355  $create_st .= "\t" . ')' . "\n";
356  }
357  $create_st .= ');' . "\n";
358  $create_st .= '$ilDB->createTable("' . $a_table . '", $fields);' . "\n";
359 
360  if ($a_file === null) {
361  echo $create_st;
362  } else {
363  fwrite($a_file, $create_st);
364  }
365  }
366 
370  public function buildAddPrimaryKeyStatement(string $a_table, $a_file = null): void
371  {
372  $pk = $this->analyzer->getPrimaryKeyInformation($a_table);
373 
374  if (is_array($pk["fields"]) && count($pk["fields"]) > 0) {
375  $pk_st = "\n" . '$pk_fields = array(';
376  $sep = "";
377  foreach ($pk["fields"] as $f => $pos) {
378  $pk_st .= $sep . '"' . $f . '"';
379  $sep = ",";
380  }
381  $pk_st .= ");\n";
382  $pk_st .= '$ilDB->addPrimaryKey("' . $a_table . '", $pk_fields);' . "\n";
383 
384  if ($a_file === null) {
385  echo $pk_st;
386  } else {
387  fwrite($a_file, $pk_st);
388  }
389  }
390  }
391 
395  public function buildAddIndexStatements(string $a_table, $a_file = null): void
396  {
397  $ind = $this->analyzer->getIndicesInformation($a_table, true);
398 
399  if (is_array($ind)) {
400  foreach ($ind as $i) {
401  if ($i["fulltext"]) {
402  $ft = ", true";
403  } else {
404  $ft = ", false";
405  }
406  $in_st = "\n" . '$in_fields = array(';
407  $sep = "";
408  foreach ($i["fields"] as $f => $pos) {
409  $in_st .= $sep . '"' . $f . '"';
410  $sep = ",";
411  }
412  $in_st .= ");\n";
413  $in_st .= '$ilDB->addIndex("' . $a_table . '", $in_fields, "' . $i["name"] . '"' . $ft . ');' . "\n";
414 
415  if ($a_file === null) {
416  echo $in_st;
417  } else {
418  fwrite($a_file, $in_st);
419  }
420  }
421  }
422  }
423 
427  private function printOrWrite(string $string, $file_handle = null): void
428  {
429  if ($file_handle === null) {
430  echo $string;
431  } else {
432  fwrite($file_handle, $string);
433  }
434  }
435 
439  public function buildAddUniqueConstraintStatements(string $a_table, $file_handle = null): void
440  {
441  $con = $this->analyzer->getConstraintsInformation($a_table, true);
442 
443  if (is_array($con)) {
444  $in_st = '';
445  foreach ($con as $i) {
446  $in_st = "\n" . '$in_fields = array(';
447  $sep = "";
448  foreach ($i["fields"] as $f => $pos) {
449  $in_st .= $sep . '"' . $f . '"';
450  $sep = ",";
451  }
452  $in_st .= ");\n";
453  $in_st .= '$ilDB->addUniqueConstraint("' . $a_table . '", $in_fields, "' . $i["name"] . '");' . "\n";
454  }
455  $this->printOrWrite($in_st, $file_handle);
456  }
457  }
458 
463  public function buildCreateSequenceStatement(string $a_table, $file_handle = null): void
464  {
465  $seq = $this->analyzer->hasSequence($a_table);
466  if ($seq !== false) {
467  $seq_st = "\n" . '$ilDB->createSequence("' . $a_table . '", ' . (int) $seq . ');' . "\n";
468 
469  $this->printOrWrite($seq_st, $file_handle);
470  }
471  }
472 
476  public function buildSingularSequenceStatement($file_handle = null): void
477  {
478  $r = $this->manager->listSequences();
479 
480  foreach ($r as $seq) {
481  if (!in_array($seq, $this->tables, true)) {
482  // 12570
483  if ($seq === "sahs_sc13_seq") {
484  continue;
485  }
486 
487  $create_st = "\n" . '$ilDB->createSequence("' . $seq . '");' . "\n";
488 
489  $this->printOrWrite($create_st, $file_handle);
490  }
491  }
492  }
493 
497  public function buildInsertStatement(string $a_table, string $a_basedir): bool
498  {
499  global $DIC;
500  $ilLogger = $DIC->logger()->root();
501 
502  $ilLogger->log('Starting export of:' . $a_table);
503 
504  $set = $this->il_db->query("SELECT * FROM " . $this->il_db->quoteIdentifier($a_table));
505  $row = 0;
506 
507  umask(0000);
508  if (!mkdir(
509  $concurrentDirectory = $a_basedir . '/' . $a_table . '_inserts',
510  fileperms($a_basedir)
511  ) && !is_dir($concurrentDirectory)) {
512  throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
513  }
514 
515  $filenum = 1;
516  while ($rec = $this->il_db->fetchAssoc($set)) {
517  $values = array();
518  foreach ($rec as $f => $v) {
519  if ($this->fields[$f]['type'] === 'text' && $this->fields[$f]['length'] >= 1000) {
520  $v = $this->shortenText($a_table, $f, $v, $this->fields[$f]['length']);
521  }
522 
523  $values[$f] = array(
524  $this->fields[$f]['type'],
525  $v,
526  );
527  }
528 
529  $rows[$a_table][$row++] = $values;
530 
531  if ($row >= 1000) {
532  $ilLogger->log('Writing insert statements after 1000 lines...');
533  $fp = fopen($a_basedir . '/' . $a_table . '_inserts/' . $filenum++ . '.data', 'wb');
534  fwrite($fp, serialize($rows));
535  fclose($fp);
536 
537  $row = 0;
538  unset($rows);
539  }
540  }
541  if (isset($rows)) {
542  $fp = fopen($a_basedir . '/' . $a_table . '_inserts/' . $filenum++ . '.data', 'wb');
543  fwrite($fp, serialize($rows) . "\n");
544  fclose($fp);
545  }
546 
547  $ilLogger->log('Finished export of: ' . $a_table);
548  if (function_exists('memory_get_usage')) {
549  $ilLogger->log('Memory usage: ' . memory_get_usage(true));
550  }
551 
552  return true;
553  }
554 
558  public function buildInsertStatements(string $a_table, $file_handle = null): void
559  {
560  if ($a_table === "lng_data") {
561  return;
562  }
563 
564  $set = $this->il_db->query("SELECT * FROM " . $this->il_db->quoteIdentifier($a_table));
565  $ins_st = "";
566  while ($rec = $this->il_db->fetchAssoc($set)) {
567  $fields = array();
568  $types = array();
569  $values = array();
570  $i_str = array();
571  foreach ($rec as $f => $v) {
572  $v = str_replace('\\', '\\\\', $v);
573  $i_str[] = "'" . $f . "' => array('" . $this->fields[$f]["type"] . "', '" . str_replace(
574  "'",
575  "\'",
576  $v
577  ) . "')";
578  }
579  $ins_st = "\n" . '$ilDB->insert("' . $a_table . '", array(' . "\n";
580  $ins_st .= implode(", ", $i_str) . "));\n";
581 
582  $this->printOrWrite($ins_st, $file_handle);
583  $ins_st = "";
584  }
585  }
586 
590  protected function shortenText(string $table, string $field, string $a_value, int $a_size): string
591  {
592  global $DIC;
593  $ilLogger = $DIC->logger()->root();
594 
595  if ($this->getTargetEncoding() === 'UTF-8') {
596  return $a_value;
597  }
598  // Convert to target encoding
599  $shortened = mb_convert_encoding($a_value, $this->getTargetEncoding(), 'UTF-8');
600  // Shorten
601  $shortened = ilStr::shortenText($shortened, 0, $a_size, $this->getTargetEncoding());
602  // Convert back to UTF-8
603  $shortened = mb_convert_encoding($shortened, 'UTF-8', $this->getTargetEncoding());
604 
605  if (strlen($a_value) != strlen($shortened)) {
606  $ilLogger->log('Table : ' . $table);
607  $ilLogger->log('Field : ' . $field);
608  $ilLogger->log('Type : ' . $this->fields[$field]['type']);
609  $ilLogger->log('Length : ' . $this->fields[$field]['length']);
610  $ilLogger->log('Before : ' . $a_value);
611  $ilLogger->log('Shortened : ' . $shortened);
612  $ilLogger->log('Strlen Before: ' . strlen($a_value));
613  $ilLogger->log('Strlen After : ' . strlen($shortened));
614  }
615 
616  return $shortened;
617  }
618 }
checkProcessing(string $a_table)
Check whether a table should be processed or not.
buildDBGenerationScript(string $a_filename="")
Build DB generation script.
printOrWrite(string $string, $file_handle=null)
$res
Definition: ltiservices.php:69
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$errors fields
Definition: imgupload.php:67
setBlackList(array $a_blacklist)
Set Table Black List.
ilDBInterface $il_db
buildSingularSequenceStatement($file_handle=null)
static lookupAbstractedTables()
buildInsertStatements(string $a_table, $file_handle=null)
buildCreateSequenceStatement(string $a_table, $file_handle=null)
setWhiteList(array $a_whitelist)
Set Table White List.
ilDBReverse $reverse
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
buildCreateTableStatement(string $a_table, $a_file=null)
ilDBManager $manager
$path
Definition: ltiservices.php:32
__construct()
Constructor.
global $DIC
Definition: feed.php:28
shortenText(string $table, string $field, string $a_value, int $a_size)
Shorten text depending on target encoding.
static shortenText(string $a_string, int $a_start_pos, int $a_num_bytes, string $a_encoding='UTF-8')
Shorten text to the given number of bytes.
setTargetEncoding(string $a_encoding)
Set the desired target encoding If the target encoding os different from UTF-8 all text values will b...
buildAddUniqueConstraintStatements(string $a_table, $file_handle=null)
$query
buildAddIndexStatements(string $a_table, $a_file=null)
$rows
Definition: xhr_table.php:10
openFile(string $a_path)
buildAddPrimaryKeyStatement(string $a_table, $a_file=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
buildInsertStatement(string $a_table, string $a_basedir)
Write seerialized insert data to array.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ilDBAnalyzer $analyzer
$i
Definition: metadata.php:41
setFilter(string $a_filter, string $a_value)