ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilDBGenerator.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
4 
14 {
15  protected $target_encoding = 'UTF-8';
16 
17  var $whitelist = array();
18  var $blacklist = array();
19  var $tables = array();
20 
24  function __construct()
25  {
26  global $ilDB;
27 
28  $this->manager = $ilDB->db->loadModule('Manager');
29  $this->reverse = $ilDB->db->loadModule('Reverse');
30  $this->il_db = $ilDB;
31  include_once("./Services/Database/classes/class.ilDBAnalyzer.php");
32  $this->analyzer = new ilDBAnalyzer();
33 
34  $this->allowed_attributes = $ilDB->getAllowedAttributes();
35  }
36 
37  public static function lookupAbstractedTables()
38  {
39  global $ilDB;
40 
41  $query = "SELECT DISTINCT(table_name) FROM abstraction_progress ";
42  $res = $ilDB->query($query);
43  $names = array();
44  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
45  {
46  $names[] = $row->table_name;
47  }
48 
49  // tables that have been already created in an abstracted
50  // way or tables that have been renamed after being abstracted
51  // (see db_update script)
52  $abs_tables = array_merge($names, array(
53  'acc_access_key',
54  'acc_user_access_key',
55  'ldap_rg_mapping',
56  'page_anchor',
57  'qpl_question_orderinghorizontal',
58  'qpl_question_fileupload',
59  'payment_vats',
60  'style_color',
61  'style_template_class',
62  'style_template',
63  'page_style_usage',
64  'style_setting',
65  'page_editor_settings',
66  'mep_data',
67  'license_data',
68  'loginname_history',
69  'mep_item',
70  'qpl_a_cloze',
71  'qpl_a_imagemap',
72  'qpl_a_matching',
73  'qpl_num_range',
74  'qpl_qst_cloze',
75  'qpl_qst_essay',
76  'qpl_qst_fileupload',
77  'qpl_qst_flash',
78  'qpl_qst_horder',
79  'qpl_qst_imagemap',
80  'qpl_qst_javaapplet',
81  'qpl_qst_matching',
82  'qpl_qst_mc',
83  'qpl_qst_numeric',
84  'qpl_qst_ordering',
85  'qpl_qst_sc',
86  'qpl_qst_textsubset',
87  'qpl_qst_type',
88  'qpl_sol_sug',
89  'udf_text',
90  'udf_clob',
91  'xmlnestedsettmp',
92  'cache_text',
93  'cache_clob',
94  'qpl_a_errortext',
95  'qpl_qst_errortext',
96  'tst_rnd_cpy',
97  'tst_rnd_qpl_title',
98  'qpl_a_mdef'
99  ));
100 
101  return $abs_tables;
102  }
103 
124  public function setTargetEncoding($a_encoding)
125  {
126  $this->target_encoding = $a_encoding;
127  }
128 
133  public function getTargetEncoding()
134  {
135  return $this->target_encoding;
136  }
137 
144  function setBlackList($a_blacklist)
145  {
146  $this->blacklist = $a_blacklist;
147  }
148 
154  function getBlackList()
155  {
156  return $this->blacklist;
157  }
158 
166  function setWhiteList($a_whitelist)
167  {
168  $this->whitelist = $a_whitelist;
169  }
170 
176  function getWhiteList()
177  {
178  return $this->whitelist;
179  }
180 
184  function setFilter($a_filter, $a_value)
185  {
186  $this->filter[$a_filter] = $a_value;
187  }
188 
192  function getTables()
193  {
194  $r = $this->manager->listTables();
195  if (!MDB2::isError($r))
196  {
197  $this->tables = $r;
198  }
199  return $this->tables;
200  }
201 
205  function checkProcessing($a_table)
206  {
207  // check black list
208  if (in_array($a_table, $this->blacklist))
209  {
210  return false;
211  }
212 
213  // check white list
214  if (count($this->whitelist) > 0 && !in_array($a_table, $this->whitelist))
215  {
216  return false;
217  }
218 
219  return true;
220  }
221 
222  protected function openFile($a_path)
223  {
224  if(1)
225  {
226  $file = fopen($a_path, "w");
227  $start.= "\t".'global $ilDB;'."\n\n";
228  fwrite($file, $start);
229  return $file;
230  }
231 
232  $file = fopen($a_path, "w");
233  $start = '<?php'."\n".'function setupILIASDatabase()'."\n{\n";
234  $start.= "\t".'global $ilDB;'."\n\n";
235  fwrite($file, $start);
236  return $file;
237  }
238 
239 
240  protected function closeFile($fp)
241  {
242  if(1)
243  {
244  #fwrite ($fp, $end);
245  fclose ($fp);
246  return;
247  }
248 
249  $end = "\n}\n?>\n";
250  fwrite ($fp, $end);
251  fclose ($fp);
252  }
253 
254 
260  function buildDBGenerationScript($a_filename = "")
261  {
262 //echo "<br>3"; flush();
263  $isDirectory = false;
264  if(@is_dir($a_filename))
265  {
266  $isDirectory = true;
267  $path = $a_filename;
268  }
269  else
270  {
271  $isDirectory = false;
272  $path = '';
273  }
274 
275  $file = "";
276  if ($a_filename != "" and !$isDirectory)
277  {
278  $file = fopen($a_filename, "w");
279 
280  $start = '<?php'."\n".'function setupILIASDatabase()'."\n{\n";
281  $start.= "\t".'global $ilDB;'."\n\n";
282  fwrite($file, $start);
283  }
284  elseif($isDirectory)
285  {
286  ;
287  }
288 
289  else
290  {
291  echo "<pre>";
292  }
293 //echo "<br>4"; flush();
294  $this->getTables();
295  foreach ($this->tables as $table)
296  {
297  if ($this->checkProcessing($table))
298  {
299  if ($a_filename != "")
300  {
301  echo "<br>$table"; flush();
302  }
303 
304  if($isDirectory)
305  {
306  $file = $this->openFile($path.'/'.$table);
307  }
308 
309  // create table statement
310  $this->buildCreateTableStatement($table, $file);
311 
312  // primary key
313  $this->buildAddPrimaryKeyStatement($table, $file);
314 
315  // indices
316  $this->buildAddIndexStatements($table, $file);
317 
318  // auto increment sequence
319  $this->buildCreateSequenceStatement($table, $file);
320 
321  // inserts
322  if($isDirectory)
323  {
324  $this->buildInsertStatement($table, $path);
325  #$this->buildInsertStatementsXML($table,$path);
326  }
327  else
328  {
329  $this->buildInsertStatements($table, $file);
330  }
331 
332  if($isDirectory)
333  {
334  $this->closeFile($file);
335  }
336 
337  }
338  else
339  {
340  if ($a_filename != "")
341  {
342  echo "<br><b>missing: ".$table."</b>"; flush();
343  }
344  }
345  }
346 
347  if ($a_filename == "")
348  {
349  echo "</pre>";
350  }
351  elseif(!$isDirectory)
352  {
353  $end = "\n}\n?>\n";
354  fwrite ($file, $end);
355  fclose ($file);
356  }
357  }
358 
365  function buildCreateTableStatement($a_table, $a_file = "")
366  {
367  $fields = $this->analyzer->getFieldInformation($a_table, true);
368  $this->fields = $fields;
369  $create_st = "\n\n//\n// ".$a_table."\n//\n";
370  $create_st.= '$fields = array ('."\n";
371  $f_sep = "";
372  foreach ($fields as $f => $def)
373  {
374 
375  $create_st.= "\t".$f_sep.'"'.$f.'" => array ('."\n";
376  $f_sep = ",";
377  $a_sep = "";
378  foreach ($def as $k => $v)
379  {
380  if ($k != "nativetype" && $k != "alt_types" && $k != "autoincrement" && !is_null($v))
381  {
382  switch ($k)
383  {
384  case "notnull":
385  case "unsigned":
386  case "fixed":
387  $v = $v ? "true" : "false";
388  break;
389 
390  case "default":
391  case "type":
392  $v = '"'.$v.'"';
393  brak;
394 
395  default:
396  break;
397  }
398  $create_st.= "\t\t".$a_sep.'"'.$k.'" => '.$v."\n";
399  $a_sep = ",";
400  }
401  }
402  $create_st.= "\t".')'."\n";
403  }
404  $create_st.= ');'."\n";
405  $create_st.= '$ilDB->createTable("'.$a_table.'", $fields);'."\n";
406 
407  if ($a_file == "")
408  {
409  echo $create_st;
410  }
411  else
412  {
413  fwrite($a_file, $create_st);
414  }
415  }
416 
423  function buildAddPrimaryKeyStatement($a_table, $a_file = "")
424  {
425  $pk = $this->analyzer->getPrimaryKeyInformation($a_table);
426 
427  if (is_array($pk["fields"]) && count($pk["fields"]) > 0)
428  {
429  $pk_st = "\n".'$pk_fields = array(';
430  $sep = "";
431  foreach ($pk["fields"] as $f => $pos)
432  {
433  $pk_st.= $sep.'"'.$f.'"';
434  $sep = ",";
435  }
436  $pk_st.= ");\n";
437  $pk_st.= '$ilDB->addPrimaryKey("'.$a_table.'", $pk_fields);'."\n";
438 
439  if ($a_file == "")
440  {
441  echo $pk_st;
442  }
443  else
444  {
445  fwrite($a_file, $pk_st);
446  }
447  }
448  }
449 
456  function buildAddIndexStatements($a_table, $a_file = "")
457  {
458  $ind = $this->analyzer->getIndicesInformation($a_table, true);
459 
460  if (is_array($ind))
461  {
462  foreach ($ind as $i)
463  {
464  if ($i["fulltext"])
465  {
466  $ft = ", true";
467  }
468  else
469  {
470  $ft = ", false";
471  }
472  $in_st = "\n".'$in_fields = array(';
473  $sep = "";
474  foreach ($i["fields"] as $f => $pos)
475  {
476  $in_st.= $sep.'"'.$f.'"';
477  $sep = ",";
478  }
479  $in_st.= ");\n";
480  $in_st.= '$ilDB->addIndex("'.$a_table.'", $in_fields, "'.$i["name"].'"'.$ft.');'."\n";
481 
482  if ($a_file == "")
483  {
484  echo $in_st;
485  }
486  else
487  {
488  fwrite($a_file, $in_st);
489  }
490  }
491  }
492  }
493 
500  function buildCreateSequenceStatement($a_table, $a_file = "")
501  {
502  $seq = $this->analyzer->hasSequence($a_table);
503  if ($seq !== false)
504  {
505  $seq_st = "\n".'$ilDB->createSequence("'.$a_table.'", '.(int) $seq.');'."\n";
506 
507  if ($a_file == "")
508  {
509  echo $seq_st;
510  }
511  else
512  {
513  fwrite($a_file, $seq_st);
514  }
515  }
516  }
517 
524  public function buildInsertStatement($a_table,$a_basedir)
525  {
526  global $ilLog;
527 
528  $ilLog->write('Starting export of:'.$a_table);
529 
530  $set = $this->il_db->query("SELECT * FROM `".$a_table."`");
531  $row = 0;
532 
533  umask(0000);
534  mkdir($a_basedir.'/'.$a_table.'_inserts',fileperms($a_basedir));
535 
536  $filenum = 1;
537  while ($rec = $this->il_db->fetchAssoc($set))
538  {
539  $values = array();
540  foreach($rec as $f => $v)
541  {
542  if($this->fields[$f]['type'] == 'text' and $this->fields[$f]['length'] >= 1000)
543  {
544  $v = $this->shortenText($a_table, $f, $v, $this->fields[$f]['length']);
545  }
546 
547  $values[$f] = array(
548  $this->fields[$f]['type'],
549  $v
550  );
551  }
552 
553  $rows[$a_table][$row++] = $values;
554 
555  if($row >= 1000)
556  {
557  $ilLog->write('Writing insert statements after 1000 lines...');
558  $fp = fopen($a_basedir.'/'.$a_table.'_inserts/'.$filenum++.'.data','w');
559  fwrite($fp,serialize((array) $rows));
560  fclose($fp);
561 
562  $row = 0;
563  unset($rows);
564  }
565 
566  }
567  if($rows)
568  {
569  $fp = fopen($a_basedir.'/'.$a_table.'_inserts/'.$filenum++.'.data','w');
570  fwrite($fp,serialize((array) $rows)."\n");
571  fclose($fp);
572  }
573 
574  $ilLog->write('Finished export of: '.$a_table);
575  if(function_exists('memory_get_usage'))
576  {
577  $ilLog->write('Memory usage: '.memory_get_usage(true));
578  }
579  return true;
580  }
581 
588  function buildInsertStatementsXML($a_table,$a_basedir)
589  {
590  global $ilLog;
591 
592  include_once './Services/Xml/classes/class.ilXmlWriter.php';
593  $w = new ilXmlWriter();
594  $w->xmlStartTag('Table',array('name' => $a_table));
595 
596  $set = $this->il_db->query("SELECT * FROM `".$a_table."`");
597  $ins_st = "";
598  $first = true;
599  while ($rec = $this->il_db->fetchAssoc($set))
600  {
601  #$ilLog->write('Num: '.$num++);
602  $w->xmlStartTag('Row');
603 
604  $fields = array();
605  $types = array();
606  $values = array();
607  foreach($rec as $f => $v)
608  {
609  if($this->fields[$f]['type'] == 'text' and $this->fields[$f]['length'] >= 1000)
610  {
611  $v = $this->shortenText($a_table, $f, $v, $this->fields[$f]['length']);
612  }
613 
614  $w->xmlElement(
615  'Value',
616  array(
617  'name' => $f,
618  'type' => $this->fields[$f]['type']
619  ),
620  $v
621  );
622  }
623 
624  $w->xmlEndTag('Row');
625  }
626  $w->xmlEndTag('Table');
627 
628  $w->xmlDumpFile($a_basedir.'/'.$a_table.'.xml',FALSE);
629  }
630 
637  function buildInsertStatements($a_table, $a_file = "")
638  {
639  if ($a_table == "lng_data")
640  {
641  return;
642  }
643 
644  $set = $this->il_db->query("SELECT * FROM `".$a_table."`");
645  $ins_st = "";
646  $first = true;
647  while ($rec = $this->il_db->fetchAssoc($set))
648  {
649  $fields = array();
650  $types = array();
651  $values = array();
652  $i_str = array();
653  foreach ($rec as $f => $v)
654  {
655  $fields[] = $f;
656  $types[] = '"'.$this->fields[$f]["type"].'"';
657  $v = str_replace('\\', '\\\\', $v);
658  $values[] = "'".str_replace("'", "\'", $v)."'";
659  $i_str[] = "'".$f."' => array('".$this->fields[$f]["type"].
660  "', '".str_replace("'", "\'", $v)."')";
661  }
662  $fields_str = "(".implode($fields, ",").")";
663  $types_str = "array(".implode($types, ",").")";
664  $values_str = "array(".implode($values, ",").")";
665  $ins_st = "\n".'$ilDB->insert("'.$a_table.'", array('."\n";
666  $ins_st.= implode($i_str, ", ")."));\n";
667  //$ins_st.= "\t".$fields_str."\n";
668  //$ins_st.= "\t".'VALUES '."(%s".str_repeat(",%s", count($fields) - 1).')"'.",\n";
669  //$ins_st.= "\t".$types_str.','.$values_str.');'."\n";
670 
671  if ($a_file == "")
672  {
673  echo $ins_st;
674  }
675  else
676  {
677  fwrite($a_file, $ins_st);
678  }
679  $ins_st = "";
680  }
681  }
682 
688  function getHTMLOverview($a_filename = "")
689  {
690  $tpl = new ilTemplate("tpl.db_overview.html", true, true, "Services/Database");
691 
692  $this->getTables();
693  $cnt = 1;
694  foreach ($this->tables as $table)
695  {
696  if ($this->checkProcessing($table))
697  {
698  // create table statement
699  if ($this->addTableToOverview($table, $tpl, $cnt))
700  {
701  $cnt++;
702  }
703  }
704  }
705 
706  $tpl->setVariable("TXT_TITLE", "ILIAS Abstract DB Tables (".ILIAS_VERSION.")");
707 
708  if ($a_filename == "")
709  {
710  echo $tpl->get();
711  }
712  }
713 
717  function addTableToOverview($a_table, $a_tpl, $a_cnt)
718  {
719  $fields = $this->analyzer->getFieldInformation($a_table);
720  $indices = $this->analyzer->getIndicesInformation($a_table);
721  $constraints = $this->analyzer->getConstraintsInformation($a_table);
722  $pk = $this->analyzer->getPrimaryKeyInformation($a_table);
723  $auto = $this->analyzer->getAutoIncrementField($a_table);
724  $has_sequence = $this->analyzer->hasSequence($a_table);
725 
726  // table filter
727  if (isset($this->filter["has_sequence"]))
728  {
729  if ((!$has_sequence && $auto == "" && $this->filter["has_sequence"]) ||
730  (($has_sequence || $auto != "") && !$this->filter["has_sequence"]))
731  {
732  return false;
733  }
734  }
735 
736  // indices
737  $indices_output = false;
738  if (is_array($indices) && count($indices) > 0 && !$this->filter["skip_indices"])
739  {
740  foreach ($indices as $index => $def)
741  {
742  $f2 = array();
743  foreach ($def["fields"] as $f => $pos)
744  {
745  $f2[] = $f;
746  }
747  $a_tpl->setCurrentBlock("index");
748  $a_tpl->setVariable("VAL_INDEX", $def["name"]);
749  $a_tpl->setVariable("VAL_FIELDS", implode($f2, ", "));
750  $a_tpl->parseCurrentBlock();
751  $indices_output = true;
752  }
753  $a_tpl->setCurrentBlock("index_table");
754  $a_tpl->parseCurrentBlock();
755  }
756 
757  // constraints
758  $constraints_output = false;
759  if (is_array($constraints) && count($constraints) > 0 && !$this->filter["skip_constraints"])
760  {
761  foreach ($constraints as $index => $def)
762  {
763  $f2 = array();
764  foreach ($def["fields"] as $f => $pos)
765  {
766  $f2[] = $f;
767  }
768  $a_tpl->setCurrentBlock("constraint");
769  $a_tpl->setVariable("VAL_CONSTRAINT", $def["name"]);
770  $a_tpl->setVariable("VAL_CTYPE", $def["type"]);
771  $a_tpl->setVariable("VAL_CFIELDS", implode($f2, ", "));
772  $a_tpl->parseCurrentBlock();
773  $constraints_output = true;
774  }
775  $a_tpl->setCurrentBlock("constraint_table");
776  $a_tpl->parseCurrentBlock();
777  }
778 
779  // fields
780  $fields_output = false;
781  foreach ($fields as $field => $def)
782  {
783  // field filter
784  if (isset($this->filter["alt_types"]))
785  {
786  if (($def["alt_types"] == "" && $this->filter["alt_types"]) ||
787  ($def["alt_types"] != "" && !$this->filter["alt_types"]))
788  {
789  continue;
790  }
791  }
792  if (isset($this->filter["type"]))
793  {
794  if ($def["type"] != $this->filter["type"])
795  {
796  continue;
797  }
798  }
799  if (isset($this->filter["nativetype"]))
800  {
801  if ($def["nativetype"] != $this->filter["nativetype"])
802  {
803  continue;
804  }
805  }
806  if (isset($this->filter["unsigned"]))
807  {
808  if ($def["unsigned"] != $this->filter["unsigned"])
809  {
810  continue;
811  }
812  }
813 
814  $a_tpl->setCurrentBlock("field");
815  if (empty($pk["fields"][$field]))
816  {
817  $a_tpl->setVariable("VAL_FIELD", strtolower($field));
818  }
819  else
820  {
821  $a_tpl->setVariable("VAL_FIELD", "<u>".strtolower($field)."</u>");
822  }
823  $a_tpl->setVariable("VAL_TYPE", $def["type"]);
824  $a_tpl->setVariable("VAL_LENGTH", (!is_null($def["length"])) ? $def["length"] : "&nbsp;");
825 
826  if (strtolower($def["default"]) == "current_timestamp")
827  {
828  //$def["default"] = "0000-00-00 00:00:00";
829  unset($def["default"]);
830  }
831 
832  $a_tpl->setVariable("VAL_DEFAULT", (!is_null($def["default"])) ? $def["default"] : "&nbsp;");
833  $a_tpl->setVariable("VAL_NOT_NULL", (!is_null($def["notnull"]))
834  ? (($def["notnull"]) ? "true" : "false")
835  : "&nbsp;");
836  $a_tpl->setVariable("VAL_FIXED", (!is_null($def["fixed"]))
837  ? (($def["fixed"]) ? "true" : "false")
838  : "&nbsp;");
839  $a_tpl->setVariable("VAL_UNSIGNED", (!is_null($def["unsigned"]))
840  ? (($def["unsigned"]) ? "true" : "false")
841  : "&nbsp;");
842  $a_tpl->setVariable("VAL_ALTERNATIVE_TYPES", ($def["alt_types"] != "") ? $def["alt_types"] : "&nbsp;");
843  $a_tpl->setVariable("VAL_NATIVETYPE", ($def["nativetype"] != "") ? $def["nativetype"] : "&nbsp;");
844  $a_tpl->parseCurrentBlock();
845  $fields_output = true;
846  }
847 
848  if ($fields_output)
849  {
850  $a_tpl->setCurrentBlock("field_table");
851  $a_tpl->parseCurrentBlock();
852  }
853 
854  // table information
855  if ($indices_output || $fields_output || $constraints_output)
856  {
857  $a_tpl->setCurrentBlock("table");
858  $a_tpl->setVariable("TXT_TABLE_NAME", strtolower($a_table));
859  if ($has_sequence || $auto != "")
860  {
861  $a_tpl->setVariable("TXT_SEQUENCE", "Has Sequence");
862  }
863  else
864  {
865  $a_tpl->setVariable("TXT_SEQUENCE", "No Sequence");
866  }
867  $a_tpl->setVariable("VAL_CNT", (int) $a_cnt);
868  $a_tpl->parseCurrentBlock();
869 
870  return true;
871  }
872 
873  return false;
874  }
875 
884  protected function shortenText($table,$field,$a_value,$a_size)
885  {
886  global $ilLog;
887 
888  if($this->getTargetEncoding() == 'UTF-8')
889  {
890  return $a_value;
891  }
892  // Convert to target encoding
893  $shortened = mb_convert_encoding($a_value, $this->getTargetEncoding(), 'UTF-8');
894  // Shorten
895  include_once './Services/Utilities/classes/class.ilStr.php';
896  $shortened = ilStr::shortenText($shortened, 0, $a_size,$this->getTargetEncoding());
897  // Convert back to UTF-8
898  $shortened = mb_convert_encoding($shortened, 'UTF-8',$this->getTargetEncoding());
899 
900  if(strlen($a_value) != strlen($shortened))
901  {
902  $ilLog->write('Table : '.$table);
903  $ilLog->write('Field : '.$field );
904  $ilLog->write('Type : '.$this->fields[$field]['type']);
905  $ilLog->write('Length : '.$this->fields[$field]['length']);
906  $ilLog->write('Before : '.$a_value);
907  $ilLog->write('Shortened : '.$shortened);
908  $ilLog->write('Strlen Before: '.strlen($a_value));
909  $ilLog->write('Strlen After : '.strlen($shortened));
910  }
911  return $shortened;
912  }
913 
914 }
915 ?>