C:/lib/adodb/adodb-xmlschema.inc.php Quellcode

adodb-xmlschema.inc.php
gehe zur Dokumentation dieser Datei
1 <?php
2 // Copyright (c) 2004 ars Cognita Inc., all rights reserved
3 /* ******************************************************************************
4  Released under both BSD license and Lesser GPL library license.
5  Whenever there is any discrepancy between the two licenses,
6  the BSD license will take precedence.
7 *******************************************************************************/
21 function _file_get_contents($file)
22 {
23  if (function_exists('file_get_contents')) return file_get_contents($file);
24 
25  $f = fopen($file,'r');
26  if (!$f) return '';
27  $t = '';
28 
29  while ($s = fread($f,100000)) $t .= $s;
30  fclose($f);
31  return $t;
32 }
33 
34 
38 if( !defined( 'XMLS_DEBUG' ) ) {
39  define( 'XMLS_DEBUG', FALSE );
40 }
41 
45 if( !defined( 'XMLS_PREFIX' ) ) {
46  define( 'XMLS_PREFIX', '%%P' );
47 }
48 
52 if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
53  define( 'XMLS_PREFIX_MAXLEN', 10 );
54 }
55 
59 if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
60  define( 'XMLS_EXECUTE_INLINE', FALSE );
61 }
62 
66 if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
67  define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
68 }
69 
73 if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
74  define( 'XMLS_SCHEMA_VERSION', '0.2' );
75 }
76 
80 if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
81  define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
82 }
83 
87 if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
88  define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
89 }
90 
94 if( !defined( '_ADODB_LAYER' ) ) {
95  require( 'adodb.inc.php' );
96  require( 'adodb-datadict.inc.php' );
97 }
98 
106 class dbObject {
107 
111  var $parent;
112 
117 
121  function dbObject( &$parent, $attributes = NULL ) {
122  $this->parent = $parent;
123  }
124 
130  function _tag_open( &$parser, $tag, $attributes ) {
131 
132  }
133 
139  function _tag_cdata( &$parser, $cdata ) {
140 
141  }
142 
148  function _tag_close( &$parser, $tag ) {
149 
150  }
151 
152  function create(&$xmls) {
153  return array();
154  }
155 
159  function destroy() {
160  unset( $this );
161  }
162 
170  function supportedPlatform( $platform = NULL ) {
171  return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
172  }
173 
180  function prefix( $name = '' ) {
181  return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
182  }
183 
190  function FieldID( $field ) {
191  return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
192  }
193 }
194 
206 class dbTable extends dbObject {
207 
211  var $name;
212 
216  var $fields = array();
217 
221  var $indexes = array();
222 
226  var $opts = array();
227 
232 
238 
243  var $drop_field = array();
244 
251  function dbTable( &$parent, $attributes = NULL ) {
252  $this->parent = $parent;
253  $this->name = $this->prefix($attributes['NAME']);
254  }
255 
262  function _tag_open( &$parser, $tag, $attributes ) {
263  $this->currentElement = strtoupper( $tag );
264 
265  switch( $this->currentElement ) {
266  case 'INDEX':
267  if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
268  xml_set_object( $parser, $this->addIndex( $attributes ) );
269  }
270  break;
271  case 'DATA':
272  if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
273  xml_set_object( $parser, $this->addData( $attributes ) );
274  }
275  break;
276  case 'DROP':
277  $this->drop();
278  break;
279  case 'FIELD':
280  // Add a field
281  $fieldName = $attributes['NAME'];
282  $fieldType = $attributes['TYPE'];
283  $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
284  $fieldOpts = isset( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
285 
286  $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
287  break;
288  case 'KEY':
289  case 'NOTNULL':
290  case 'AUTOINCREMENT':
291  // Add a field option
292  $this->addFieldOpt( $this->current_field, $this->currentElement );
293  break;
294  case 'DEFAULT':
295  // Add a field option to the table object
296 
297  // Work around ADOdb datadict issue that misinterprets empty strings.
298  if( $attributes['VALUE'] == '' ) {
299  $attributes['VALUE'] = " '' ";
300  }
301 
302  $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
303  break;
304  case 'DEFDATE':
305  case 'DEFTIMESTAMP':
306  // Add a field option to the table object
307  $this->addFieldOpt( $this->current_field, $this->currentElement );
308  break;
309  default:
310  // print_r( array( $tag, $attributes ) );
311  }
312  }
313 
319  function _tag_cdata( &$parser, $cdata ) {
320  switch( $this->currentElement ) {
321  // Table constraint
322  case 'CONSTRAINT':
323  if( isset( $this->current_field ) ) {
324  $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
325  } else {
326  $this->addTableOpt( $cdata );
327  }
328  break;
329  // Table option
330  case 'OPT':
331  $this->addTableOpt( $cdata );
332  break;
333  default:
334 
335  }
336  }
337 
343  function _tag_close( &$parser, $tag ) {
344  $this->currentElement = '';
345 
346  switch( strtoupper( $tag ) ) {
347  case 'TABLE':
348  $this->parent->addSQL( $this->create( $this->parent ) );
349  xml_set_object( $parser, $this->parent );
350  $this->destroy();
351  break;
352  case 'FIELD':
353  unset($this->current_field);
354  break;
355 
356  }
357  }
358 
365  function addIndex( $attributes ) {
366  $name = strtoupper( $attributes['NAME'] );
367  $this->indexes[$name] = new dbIndex( $this, $attributes );
368  return $this->indexes[$name];
369  }
370 
377  function addData( $attributes ) {
378  if( !isset( $this->data ) ) {
379  $this->data = new dbData( $this, $attributes );
380  }
381  return $this->data;
382  }
383 
413  function addField( $name, $type, $size = NULL, $opts = NULL ) {
414  $field_id = $this->FieldID( $name );
415 
416  // Set the field index so we know where we are
417  $this->current_field = $field_id;
418 
419  // Set the field name (required)
420  $this->fields[$field_id]['NAME'] = $name;
421 
422  // Set the field type (required)
423  $this->fields[$field_id]['TYPE'] = $type;
424 
425  // Set the field size (optional)
426  if( isset( $size ) ) {
427  $this->fields[$field_id]['SIZE'] = $size;
428  }
429 
430  // Set the field options
431  if( isset( $opts ) ) {
432  $this->fields[$field_id]['OPTS'][] = $opts;
433  }
434  }
435 
447  function addFieldOpt( $field, $opt, $value = NULL ) {
448  if( !isset( $value ) ) {
449  $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
450  // Add the option and value
451  } else {
452  $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
453  }
454  }
455 
465  function addTableOpt( $opt ) {
466  if(isset($this->currentPlatform)) {
467  $this->opts[$this->parent->db->databaseType] = $opt;
468  }
469  return $this->opts;
470  }
471 
472 
479  function create( &$xmls ) {
480  $sql = array();
481 
482  // drop any existing indexes
483  if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
484  foreach( $legacy_indexes as $index => $index_details ) {
485  $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
486  }
487  }
488 
489  // remove fields to be dropped from table object
490  foreach( $this->drop_field as $field ) {
491  unset( $this->fields[$field] );
492  }
493 
494  // if table exists
495  if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
496  // drop table
497  if( $this->drop_table ) {
498  $sql[] = $xmls->dict->DropTableSQL( $this->name );
499 
500  return $sql;
501  }
502 
503  // drop any existing fields not in schema
504  foreach( $legacy_fields as $field_id => $field ) {
505  if( !isset( $this->fields[$field_id] ) ) {
506  $sql[] = $xmls->dict->DropColumnSQL( $this->name, '`'.$field->name.'`' );
507  }
508  }
509  // if table doesn't exist
510  } else {
511  if( $this->drop_table ) {
512  return $sql;
513  }
514 
515  $legacy_fields = array();
516  }
517 
518  // Loop through the field specifier array, building the associative array for the field options
519  $fldarray = array();
520 
521  foreach( $this->fields as $field_id => $finfo ) {
522  // Set an empty size if it isn't supplied
523  if( !isset( $finfo['SIZE'] ) ) {
524  $finfo['SIZE'] = '';
525  }
526 
527  // Initialize the field array with the type and size
528  $fldarray[$field_id] = array(
529  'NAME' => $finfo['NAME'],
530  'TYPE' => $finfo['TYPE'],
531  'SIZE' => $finfo['SIZE']
532  );
533 
534  // Loop through the options array and add the field options.
535  if( isset( $finfo['OPTS'] ) ) {
536  foreach( $finfo['OPTS'] as $opt ) {
537  // Option has an argument.
538  if( is_array( $opt ) ) {
539  $key = key( $opt );
540  $value = $opt[key( $opt )];
541  @$fldarray[$field_id][$key] .= $value;
542  // Option doesn't have arguments
543  } else {
544  $fldarray[$field_id][$opt] = $opt;
545  }
546  }
547  }
548  }
549 
550  if( empty( $legacy_fields ) ) {
551  // Create the new table
552  $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
553  logMsg( end( $sql ), 'Generated CreateTableSQL' );
554  } else {
555  // Upgrade an existing table
556  logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
557  switch( $xmls->upgrade ) {
558  // Use ChangeTableSQL
559  case 'ALTER':
560  logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
561  $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
562  break;
563  case 'REPLACE':
564  logMsg( 'Doing upgrade REPLACE (testing)' );
565  $sql[] = $xmls->dict->DropTableSQL( $this->name );
566  $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
567  break;
568  // ignore table
569  default:
570  return array();
571  }
572  }
573 
574  foreach( $this->indexes as $index ) {
575  $sql[] = $index->create( $xmls );
576  }
577 
578  if( isset( $this->data ) ) {
579  $sql[] = $this->data->create( $xmls );
580  }
581 
582  return $sql;
583  }
584 
588  function drop() {
589  if( isset( $this->current_field ) ) {
590  // Drop the current field
591  logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
592  // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
593  $this->drop_field[$this->current_field] = $this->current_field;
594  } else {
595  // Drop the current table
596  logMsg( "Dropping table '{$this->name}'" );
597  // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
598  $this->drop_table = TRUE;
599  }
600  }
601 }
602 
614 class dbIndex extends dbObject {
615 
619  var $name;
620 
624  var $opts = array();
625 
629  var $columns = array();
630 
635  var $drop = FALSE;
636 
645  function dbIndex( &$parent, $attributes = NULL ) {
646  $this->parent = $parent;
647 
648  $this->name = $this->prefix ($attributes['NAME']);
649  }
650 
659  function _tag_open( &$parser, $tag, $attributes ) {
660  $this->currentElement = strtoupper( $tag );
661 
662  switch( $this->currentElement ) {
663  case 'DROP':
664  $this->drop();
665  break;
666  case 'CLUSTERED':
667  case 'BITMAP':
668  case 'UNIQUE':
669  case 'FULLTEXT':
670  case 'HASH':
671  // Add index Option
672  $this->addIndexOpt( $this->currentElement );
673  break;
674  default:
675  // print_r( array( $tag, $attributes ) );
676  }
677  }
678 
686  function _tag_cdata( &$parser, $cdata ) {
687  switch( $this->currentElement ) {
688  // Index field name
689  case 'COL':
690  $this->addField( $cdata );
691  break;
692  default:
693 
694  }
695  }
696 
702  function _tag_close( &$parser, $tag ) {
703  $this->currentElement = '';
704 
705  switch( strtoupper( $tag ) ) {
706  case 'INDEX':
707  xml_set_object( $parser, $this->parent );
708  break;
709  }
710  }
711 
718  function addField( $name ) {
719  $this->columns[$this->FieldID( $name )] = $name;
720 
721  // Return the field list
722  return $this->columns;
723  }
724 
731  function addIndexOpt( $opt ) {
732  $this->opts[] = $opt;
733 
734  // Return the options list
735  return $this->opts;
736  }
737 
744  function create( &$xmls ) {
745  if( $this->drop ) {
746  return NULL;
747  }
748 
749  // eliminate any columns that aren't in the table
750  foreach( $this->columns as $id => $col ) {
751  if( !isset( $this->parent->fields[$id] ) ) {
752  unset( $this->columns[$id] );
753  }
754  }
755 
756  return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
757  }
758 
762  function drop() {
763  $this->drop = TRUE;
764  }
765 }
766 
775 class dbData extends dbObject {
776 
777  var $data = array();
778 
779  var $row;
780 
789  function dbData( &$parent, $attributes = NULL ) {
790  $this->parent = $parent;
791  }
792 
801  function _tag_open( &$parser, $tag, $attributes ) {
802  $this->currentElement = strtoupper( $tag );
803 
804  switch( $this->currentElement ) {
805  case 'ROW':
806  $this->row = count( $this->data );
807  $this->data[$this->row] = array();
808  break;
809  case 'F':
810  $this->addField($attributes);
811  default:
812  // print_r( array( $tag, $attributes ) );
813  }
814  }
815 
823  function _tag_cdata( &$parser, $cdata ) {
824  switch( $this->currentElement ) {
825  // Index field name
826  case 'F':
827  $this->addData( $cdata );
828  break;
829  default:
830 
831  }
832  }
833 
839  function _tag_close( &$parser, $tag ) {
840  $this->currentElement = '';
841 
842  switch( strtoupper( $tag ) ) {
843  case 'DATA':
844  xml_set_object( $parser, $this->parent );
845  break;
846  }
847  }
848 
855  function addField( $attributes ) {
856  if( isset( $attributes['NAME'] ) ) {
857  $name = $attributes['NAME'];
858  } else {
859  $name = count($this->data[$this->row]);
860  }
861 
862  // Set the field index so we know where we are
863  $this->current_field = $this->FieldID( $name );
864  }
865 
872  function addData( $cdata ) {
873  if( !isset( $this->data[$this->row] ) ) {
874  $this->data[$this->row] = array();
875  }
876 
877  if( !isset( $this->data[$this->row][$this->current_field] ) ) {
878  $this->data[$this->row][$this->current_field] = '';
879  }
880 
881  $this->data[$this->row][$this->current_field] .= $cdata;
882  }
883 
890  function create( &$xmls ) {
891  $table = $xmls->dict->TableName($this->parent->name);
892  $table_field_count = count($this->parent->fields);
893  $sql = array();
894 
895  // eliminate any columns that aren't in the table
896  foreach( $this->data as $row ) {
897  $table_fields = $this->parent->fields;
898  $fields = array();
899 
900  foreach( $row as $field_id => $field_data ) {
901  if( !array_key_exists( $field_id, $table_fields ) ) {
902  if( is_numeric( $field_id ) ) {
903  $field_id = reset( array_keys( $table_fields ) );
904  } else {
905  continue;
906  }
907  }
908 
909  $name = $table_fields[$field_id]['NAME'];
910 
911  switch( $table_fields[$field_id]['TYPE'] ) {
912  case 'C':
913  case 'C2':
914  case 'X':
915  case 'X2':
916  $fields[$name] = $xmls->db->qstr( $field_data );
917  break;
918  case 'I':
919  case 'I1':
920  case 'I2':
921  case 'I4':
922  case 'I8':
923  $fields[$name] = intval($field_data);
924  break;
925  default:
926  $fields[$name] = $field_data;
927  }
928 
929  unset($table_fields[$field_id]);
930  }
931 
932  // check that at least 1 column is specified
933  if( empty( $fields ) ) {
934  continue;
935  }
936 
937  // check that no required columns are missing
938  if( count( $fields ) < $table_field_count ) {
939  foreach( $table_fields as $field ) {
940  if (isset( $field['OPTS'] ))
941  if( ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
942  continue(2);
943  }
944  }
945  }
946 
947  $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
948  }
949 
950  return $sql;
951  }
952 }
953 
960 class dbQuerySet extends dbObject {
961 
965  var $queries = array();
966 
970  var $query;
971 
975  var $prefixKey = '';
976 
980  var $prefixMethod = 'AUTO';
981 
988  function dbQuerySet( &$parent, $attributes = NULL ) {
989  $this->parent = $parent;
990 
991  // Overrides the manual prefix key
992  if( isset( $attributes['KEY'] ) ) {
993  $this->prefixKey = $attributes['KEY'];
994  }
995 
996  $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
997 
998  // Enables or disables automatic prefix prepending
999  switch( $prefixMethod ) {
1000  case 'AUTO':
1001  $this->prefixMethod = 'AUTO';
1002  break;
1003  case 'MANUAL':
1004  $this->prefixMethod = 'MANUAL';
1005  break;
1006  case 'NONE':
1007  $this->prefixMethod = 'NONE';
1008  break;
1009  }
1010  }
1011 
1018  function _tag_open( &$parser, $tag, $attributes ) {
1019  $this->currentElement = strtoupper( $tag );
1020 
1021  switch( $this->currentElement ) {
1022  case 'QUERY':
1023  // Create a new query in a SQL queryset.
1024  // Ignore this query set if a platform is specified and it's different than the
1025  // current connection platform.
1026  if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
1027  $this->newQuery();
1028  } else {
1029  $this->discardQuery();
1030  }
1031  break;
1032  default:
1033  // print_r( array( $tag, $attributes ) );
1034  }
1035  }
1036 
1040  function _tag_cdata( &$parser, $cdata ) {
1041  switch( $this->currentElement ) {
1042  // Line of queryset SQL data
1043  case 'QUERY':
1044  $this->buildQuery( $cdata );
1045  break;
1046  default:
1047 
1048  }
1049  }
1050 
1056  function _tag_close( &$parser, $tag ) {
1057  $this->currentElement = '';
1058 
1059  switch( strtoupper( $tag ) ) {
1060  case 'QUERY':
1061  // Add the finished query to the open query set.
1062  $this->addQuery();
1063  break;
1064  case 'SQL':
1065  $this->parent->addSQL( $this->create( $this->parent ) );
1066  xml_set_object( $parser, $this->parent );
1067  $this->destroy();
1068  break;
1069  default:
1070 
1071  }
1072  }
1073 
1079  function newQuery() {
1080  $this->query = '';
1081 
1082  return TRUE;
1083  }
1084 
1090  function discardQuery() {
1091  unset( $this->query );
1092 
1093  return TRUE;
1094  }
1095 
1102  function buildQuery( $sql = NULL ) {
1103  if( !isset( $this->query ) OR empty( $sql ) ) {
1104  return FALSE;
1105  }
1106 
1107  $this->query .= $sql;
1108 
1109  return $this->query;
1110  }
1111 
1117  function addQuery() {
1118  if( !isset( $this->query ) ) {
1119  return FALSE;
1120  }
1121 
1122  $this->queries[] = $return = trim($this->query);
1123 
1124  unset( $this->query );
1125 
1126  return $return;
1127  }
1128 
1135  function create( &$xmls ) {
1136  foreach( $this->queries as $id => $query ) {
1137  switch( $this->prefixMethod ) {
1138  case 'AUTO':
1139  // Enable auto prefix replacement
1140 
1141  // Process object prefix.
1142  // Evaluate SQL statements to prepend prefix to objects
1143  $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
1144  $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
1145  $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
1146 
1147  // SELECT statements aren't working yet
1148  #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
1149 
1150  case 'MANUAL':
1151  // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
1152  // If prefixKey is not set, we use the default constant XMLS_PREFIX
1153  if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
1154  // Enable prefix override
1155  $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
1156  } else {
1157  // Use default replacement
1158  $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
1159  }
1160  }
1161 
1162  $this->queries[$id] = trim( $query );
1163  }
1164 
1165  // Return the query set array
1166  return $this->queries;
1167  }
1168 
1177  function prefixQuery( $regex, $query, $prefix = NULL ) {
1178  if( !isset( $prefix ) ) {
1179  return $query;
1180  }
1181 
1182  if( preg_match( $regex, $query, $match ) ) {
1183  $preamble = $match[1];
1184  $postamble = $match[5];
1185  $objectList = explode( ',', $match[3] );
1186  // $prefix = $prefix . '_';
1187 
1188  $prefixedList = '';
1189 
1190  foreach( $objectList as $object ) {
1191  if( $prefixedList !== '' ) {
1192  $prefixedList .= ', ';
1193  }
1194 
1195  $prefixedList .= $prefix . trim( $object );
1196  }
1197 
1198  $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
1199  }
1200 
1201  return $query;
1202  }
1203 }
1204 
1218 class adoSchema {
1219 
1225 
1230  var $db;
1231 
1236  var $dict;
1237 
1243 
1248  var $upgrade = '';
1249 
1254  var $objectPrefix = '';
1255 
1260  var $mgq;
1261 
1266  var $debug;
1267 
1272  var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
1273 
1279 
1284 
1289 
1294 
1304  function adoSchema( $db ) {
1305  // Initialize the environment
1306  $this->mgq = get_magic_quotes_runtime();
1307  ini_set("magic_quotes_runtime", 0);
1308  #set_magic_quotes_runtime(0);
1309 
1310  $this->db = $db;
1311  $this->debug = $this->db->debug;
1312  $this->dict = NewDataDictionary( $this->db );
1313  $this->sqlArray = array();
1314  $this->schemaVersion = XMLS_SCHEMA_VERSION;
1315  $this->executeInline( XMLS_EXECUTE_INLINE );
1316  $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
1317  $this->setUpgradeMethod();
1318  }
1319 
1336  function SetUpgradeMethod( $method = '' ) {
1337  if( !is_string( $method ) ) {
1338  return FALSE;
1339  }
1340 
1341  $method = strtoupper( $method );
1342 
1343  // Handle the upgrade methods
1344  switch( $method ) {
1345  case 'ALTER':
1346  $this->upgrade = $method;
1347  break;
1348  case 'REPLACE':
1349  $this->upgrade = $method;
1350  break;
1351  case 'BEST':
1352  $this->upgrade = 'ALTER';
1353  break;
1354  case 'NONE':
1355  $this->upgrade = 'NONE';
1356  break;
1357  default:
1358  // Use default if no legitimate method is passed.
1359  $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
1360  }
1361 
1362  return $this->upgrade;
1363  }
1364 
1378  function ExecuteInline( $mode = NULL ) {
1379  if( is_bool( $mode ) ) {
1380  $this->executeInline = $mode;
1381  }
1382 
1383  return $this->executeInline;
1384  }
1385 
1399  function ContinueOnError( $mode = NULL ) {
1400  if( is_bool( $mode ) ) {
1401  $this->continueOnError = $mode;
1402  }
1403 
1404  return $this->continueOnError;
1405  }
1406 
1418  function ParseSchema( $filename, $returnSchema = FALSE ) {
1419  return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
1420  }
1421 
1435  function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
1436  // Open the file
1437  if( !($fp = fopen( $filename, 'r' )) ) {
1438  // die( 'Unable to open file' );
1439  return FALSE;
1440  }
1441 
1442  // do version detection here
1443  if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
1444  return FALSE;
1445  }
1446 
1447  if ( $returnSchema )
1448  {
1449  $xmlstring = '';
1450  while( $data = fread( $fp, 100000 ) ) {
1451  $xmlstring .= $data;
1452  }
1453  return $xmlstring;
1454  }
1455 
1456  $this->success = 2;
1457 
1458  $xmlParser = $this->create_parser();
1459 
1460  // Process the file
1461  while( $data = fread( $fp, 4096 ) ) {
1462  if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
1463  die( sprintf(
1464  "XML error: %s at line %d",
1465  xml_error_string( xml_get_error_code( $xmlParser) ),
1466  xml_get_current_line_number( $xmlParser)
1467  ) );
1468  }
1469  }
1470 
1471  xml_parser_free( $xmlParser );
1472 
1473  return $this->sqlArray;
1474  }
1475 
1487  function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
1488  if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
1489  return FALSE;
1490  }
1491 
1492  // do version detection here
1493  if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
1494  return FALSE;
1495  }
1496 
1497  if ( $returnSchema )
1498  {
1499  return $xmlstring;
1500  }
1501 
1502  $this->success = 2;
1503 
1504  $xmlParser = $this->create_parser();
1505 
1506  if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
1507  die( sprintf(
1508  "XML error: %s at line %d",
1509  xml_error_string( xml_get_error_code( $xmlParser) ),
1510  xml_get_current_line_number( $xmlParser)
1511  ) );
1512  }
1513 
1514  xml_parser_free( $xmlParser );
1515 
1516  return $this->sqlArray;
1517  }
1518 
1530  function RemoveSchema( $filename, $returnSchema = FALSE ) {
1531  return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
1532  }
1533 
1545  function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
1546 
1547  // grab current version
1548  if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
1549  return FALSE;
1550  }
1551 
1552  return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
1553  }
1554 
1568  function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) {
1569  if( !is_bool( $continueOnErr ) ) {
1570  $continueOnErr = $this->ContinueOnError();
1571  }
1572 
1573  if( !isset( $sqlArray ) ) {
1575  }
1576 
1577  if( !is_array( $sqlArray ) ) {
1578  $this->success = 0;
1579  } else {
1580  $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
1581  }
1582 
1583  return $this->success;
1584  }
1585 
1595  function PrintSQL( $format = 'NONE' ) {
1596  $sqlArray = null;
1597  return $this->getSQL( $format, $sqlArray );
1598  }
1599 
1609  function SaveSQL( $filename = './schema.sql' ) {
1610 
1611  if( !isset( $sqlArray ) ) {
1613  }
1614  if( !isset( $sqlArray ) ) {
1615  return FALSE;
1616  }
1617 
1618  $fp = fopen( $filename, "w" );
1619 
1620  foreach( $sqlArray as $key => $query ) {
1621  fwrite( $fp, $query . ";\n" );
1622  }
1623  fclose( $fp );
1624  }
1625 
1633  function create_parser() {
1634  // Create the parser
1635  $xmlParser = xml_parser_create();
1636  xml_set_object( $xmlParser, $this );
1637 
1638  // Initialize the XML callback functions
1639  xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
1640  xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
1641 
1642  return $xmlParser;
1643  }
1644 
1650  function _tag_open( &$parser, $tag, $attributes ) {
1651  switch( strtoupper( $tag ) ) {
1652  case 'TABLE':
1653  $this->obj = new dbTable( $this, $attributes );
1654  xml_set_object( $parser, $this->obj );
1655  break;
1656  case 'SQL':
1657  if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
1658  $this->obj = new dbQuerySet( $this, $attributes );
1659  xml_set_object( $parser, $this->obj );
1660  }
1661  break;
1662  default:
1663  // print_r( array( $tag, $attributes ) );
1664  }
1665 
1666  }
1667 
1673  function _tag_cdata( &$parser, $cdata ) {
1674  }
1675 
1682  function _tag_close( &$parser, $tag ) {
1683 
1684  }
1685 
1702  function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
1703 
1704  // grab current version
1705  if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
1706  return FALSE;
1707  }
1708 
1709  if( !isset ($newVersion) ) {
1710  $newVersion = $this->schemaVersion;
1711  }
1712 
1713  if( $version == $newVersion ) {
1714  $result = $schema;
1715  } else {
1716  $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
1717  }
1718 
1719  if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
1720  fwrite( $fp, $result );
1721  fclose( $fp );
1722  }
1723 
1724  return $result;
1725  }
1726 
1727  // compat for pre-4.3 - jlim
1728  function _file_get_contents($path)
1729  {
1730  if (function_exists('file_get_contents')) return file_get_contents($path);
1731  return join('',file($path));
1732  }
1733 
1750  function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
1751 
1752  // grab current version
1753  if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
1754  return FALSE;
1755  }
1756 
1757  if( !isset ($newVersion) ) {
1758  $newVersion = $this->schemaVersion;
1759  }
1760 
1761  if( $version == $newVersion ) {
1762  $result = _file_get_contents( $filename );
1763 
1764  // remove unicode BOM if present
1765  if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
1766  $result = substr( $result, 3 );
1767  }
1768  } else {
1769  $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
1770  }
1771 
1772  if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
1773  fwrite( $fp, $result );
1774  fclose( $fp );
1775  }
1776 
1777  return $result;
1778  }
1779 
1780  function TransformSchema( $schema, $xsl, $schematype='string' )
1781  {
1782  // Fail if XSLT extension is not available
1783  if( ! function_exists( 'xslt_create' ) ) {
1784  return FALSE;
1785  }
1786 
1787  $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
1788 
1789  // look for xsl
1790  if( !is_readable( $xsl_file ) ) {
1791  return FALSE;
1792  }
1793 
1794  switch( $schematype )
1795  {
1796  case 'file':
1797  if( !is_readable( $schema ) ) {
1798  return FALSE;
1799  }
1800 
1801  $schema = _file_get_contents( $schema );
1802  break;
1803  case 'string':
1804  default:
1805  if( !is_string( $schema ) ) {
1806  return FALSE;
1807  }
1808  }
1809 
1810  $arguments = array (
1811  '/_xml' => $schema,
1812  '/_xsl' => _file_get_contents( $xsl_file )
1813  );
1814 
1815  // create an XSLT processor
1816  $xh = xslt_create ();
1817 
1818  // set error handler
1819  xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
1820 
1821  // process the schema
1822  $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);
1823 
1824  xslt_free ($xh);
1825 
1826  return $result;
1827  }
1828 
1839  function xslt_error_handler( $parser, $errno, $level, $fields ) {
1840  if( is_array( $fields ) ) {
1841  $msg = array(
1842  'Message Type' => ucfirst( $fields['msgtype'] ),
1843  'Message Code' => $fields['code'],
1844  'Message' => $fields['msg'],
1845  'Error Number' => $errno,
1846  'Level' => $level
1847  );
1848 
1849  switch( $fields['URI'] ) {
1850  case 'arg:/_xml':
1851  $msg['Input'] = 'XML';
1852  break;
1853  case 'arg:/_xsl':
1854  $msg['Input'] = 'XSL';
1855  break;
1856  default:
1857  $msg['Input'] = $fields['URI'];
1858  }
1859 
1860  $msg['Line'] = $fields['line'];
1861  } else {
1862  $msg = array(
1863  'Message Type' => 'Error',
1864  'Error Number' => $errno,
1865  'Level' => $level,
1866  'Fields' => var_export( $fields, TRUE )
1867  );
1868  }
1869 
1870  $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
1871  . '<table>' . "\n";
1872 
1873  foreach( $msg as $label => $details ) {
1874  $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
1875  }
1876 
1877  $error_details .= '</table>';
1878 
1879  trigger_error( $error_details, E_USER_ERROR );
1880  }
1881 
1891  function SchemaFileVersion( $filename ) {
1892  // Open the file
1893  if( !($fp = fopen( $filename, 'r' )) ) {
1894  // die( 'Unable to open file' );
1895  return FALSE;
1896  }
1897 
1898  // Process the file
1899  while( $data = fread( $fp, 4096 ) ) {
1900  if( preg_match( $this->versionRegex, $data, $matches ) ) {
1901  return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
1902  }
1903  }
1904 
1905  return FALSE;
1906  }
1907 
1917  function SchemaStringVersion( $xmlstring ) {
1918  if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
1919  return FALSE;
1920  }
1921 
1922  if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
1923  return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
1924  }
1925 
1926  return FALSE;
1927  }
1928 
1939  function ExtractSchema( $data = FALSE ) {
1940  $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
1941 
1942  $schema = '<?xml version="1.0"?>' . "\n"
1943  . '<schema version="' . $this->schemaVersion . '">' . "\n";
1944 
1945  if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
1946  foreach( $tables as $table ) {
1947  $schema .= ' <table name="' . $table . '">' . "\n";
1948 
1949  // grab details from database
1950  $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE 1=1' );
1951  $fields = $this->db->MetaColumns( $table );
1952  $indexes = $this->db->MetaIndexes( $table );
1953 
1954  if( is_array( $fields ) ) {
1955  foreach( $fields as $details ) {
1956  $extra = '';
1957  $content = array();
1958 
1959  if( $details->max_length > 0 ) {
1960  $extra .= ' size="' . $details->max_length . '"';
1961  }
1962 
1963  if( $details->primary_key ) {
1964  $content[] = '<KEY/>';
1965  } elseif( $details->not_null ) {
1966  $content[] = '<NOTNULL/>';
1967  }
1968 
1969  if( $details->has_default ) {
1970  $content[] = '<DEFAULT value="' . $details->default_value . '"/>';
1971  }
1972 
1973  if( $details->auto_increment ) {
1974  $content[] = '<AUTOINCREMENT/>';
1975  }
1976 
1977  // this stops the creation of 'R' columns,
1978  // AUTOINCREMENT is used to create auto columns
1979  $details->primary_key = 0;
1980  $type = $rs->MetaType( $details );
1981 
1982  $schema .= ' <field name="' . $details->name . '" type="' . $type . '"' . $extra . '>';
1983 
1984  if( !empty( $content ) ) {
1985  $schema .= "\n " . implode( "\n ", $content ) . "\n ";
1986  }
1987 
1988  $schema .= '</field>' . "\n";
1989  }
1990  }
1991 
1992  if( is_array( $indexes ) ) {
1993  foreach( $indexes as $index => $details ) {
1994  $schema .= ' <index name="' . $index . '">' . "\n";
1995 
1996  if( $details['unique'] ) {
1997  $schema .= ' <UNIQUE/>' . "\n";
1998  }
1999 
2000  foreach( $details['columns'] as $column ) {
2001  $schema .= ' <col>' . $column . '</col>' . "\n";
2002  }
2003 
2004  $schema .= ' </index>' . "\n";
2005  }
2006  }
2007 
2008  if( $data ) {
2009  $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
2010 
2011  if( is_object( $rs ) ) {
2012  $schema .= ' <data>' . "\n";
2013 
2014  while( $row = $rs->FetchRow() ) {
2015  foreach( $row as $key => $val ) {
2016  $row[$key] = htmlentities($val);
2017  }
2018 
2019  $schema .= ' <row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n";
2020  }
2021 
2022  $schema .= ' </data>' . "\n";
2023  }
2024  }
2025 
2026  $schema .= ' </table>' . "\n";
2027  }
2028  }
2029 
2030  $this->db->SetFetchMode( $old_mode );
2031 
2032  $schema .= '</schema>';
2033  return $schema;
2034  }
2035 
2046  function SetPrefix( $prefix = '', $underscore = TRUE ) {
2047  switch( TRUE ) {
2048  // clear prefix
2049  case empty( $prefix ):
2050  logMsg( 'Cleared prefix' );
2051  $this->objectPrefix = '';
2052  return TRUE;
2053  // prefix too long
2054  case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
2055  // prefix contains invalid characters
2056  case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
2057  logMsg( 'Invalid prefix: ' . $prefix );
2058  return FALSE;
2059  }
2060 
2061  if( $underscore AND substr( $prefix, -1 ) != '_' ) {
2062  $prefix .= '_';
2063  }
2064 
2065  // prefix valid
2066  logMsg( 'Set prefix: ' . $prefix );
2067  $this->objectPrefix = $prefix;
2068  return TRUE;
2069  }
2070 
2079  function prefix( $name = '' ) {
2080  // if prefix is set
2081  if( !empty( $this->objectPrefix ) ) {
2082  // Prepend the object prefix to the table name
2083  // prepend after quote if used
2084  return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
2085  }
2086 
2087  // No prefix set. Use name provided.
2088  return $name;
2089  }
2090 
2099  function supportedPlatform( $platform = NULL ) {
2100  $regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
2101 
2102  if( !isset( $platform ) OR preg_match( $regex, $platform ) ) {
2103  logMsg( "Platform $platform is supported" );
2104  return TRUE;
2105  } else {
2106  logMsg( "Platform $platform is NOT supported" );
2107  return FALSE;
2108  }
2109  }
2110 
2116  function clearSQL() {
2117  $this->sqlArray = array();
2118  }
2119 
2128  function addSQL( $sql = NULL ) {
2129  if( is_array( $sql ) ) {
2130  foreach( $sql as $line ) {
2131  $this->addSQL( $line );
2132  }
2133 
2134  return TRUE;
2135  }
2136 
2137  if( is_string( $sql ) ) {
2138  $this->sqlArray[] = $sql;
2139 
2140  // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
2141  if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
2142  $saved = $this->db->debug;
2143  $this->db->debug = $this->debug;
2144  $ok = $this->db->Execute( $sql );
2145  $this->db->debug = $saved;
2146 
2147  if( !$ok ) {
2148  if( $this->debug ) {
2149  ADOConnection::outp( $this->db->ErrorMsg() );
2150  }
2151 
2152  $this->success = 1;
2153  }
2154  }
2155 
2156  return TRUE;
2157  }
2158 
2159  return FALSE;
2160  }
2161 
2170  function getSQL( $format = NULL, $sqlArray = NULL ) {
2171  if( !is_array( $sqlArray ) ) {
2173  }
2174 
2175  if( !is_array( $sqlArray ) ) {
2176  return FALSE;
2177  }
2178 
2179  switch( strtolower( $format ) ) {
2180  case 'string':
2181  case 'text':
2182  return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
2183  case'html':
2184  return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
2185  }
2186 
2187  return $this->sqlArray;
2188  }
2189 
2196  function Destroy() {
2197  ini_set("magic_quotes_runtime", $this->mgq );
2198  #set_magic_quotes_runtime( $this->mgq );
2199  unset( $this );
2200  }
2201 }
2202 
2208 function logMsg( $msg, $title = NULL, $force = FALSE ) {
2209  if( XMLS_DEBUG or $force ) {
2210  echo '<pre>';
2211 
2212  if( isset( $title ) ) {
2213  echo '<h3>' . htmlentities( $title ) . '</h3>';
2214  }
2215 
2216  if( is_object( $this ) ) {
2217  echo '[' . get_class( $this ) . '] ';
2218  }
2219 
2220  print_r( $msg );
2221 
2222  echo '</pre>';
2223  }
2224 }
2225 ?>




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.