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