MDB
[ class tree: MDB ] [ index: MDB ] [ all elements ]

Source for file Parser.php

Documentation is available at Parser.php

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP Version 4                                                        |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
  6. // | Stig. S. Bakken, Lukas Smith                                         |
  7. // | All rights reserved.                                                 |
  8. // +----------------------------------------------------------------------+
  9. // | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
  10. // | API as well as database abstraction for PHP applications.            |
  11. // | This LICENSE is in the BSD license style.                            |
  12. // |                                                                      |
  13. // | Redistribution and use in source and binary forms, with or without   |
  14. // | modification, are permitted provided that the following conditions   |
  15. // | are met:                                                             |
  16. // |                                                                      |
  17. // | Redistributions of source code must retain the above copyright       |
  18. // | notice, this list of conditions and the following disclaimer.        |
  19. // |                                                                      |
  20. // | Redistributions in binary form must reproduce the above copyright    |
  21. // | notice, this list of conditions and the following disclaimer in the  |
  22. // | documentation and/or other materials provided with the distribution. |
  23. // |                                                                      |
  24. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  25. // | Lukas Smith nor the names of his contributors may be used to endorse |
  26. // | or promote products derived from this software without specific prior|
  27. // | written permission.                                                  |
  28. // |                                                                      |
  29. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  30. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  31. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  32. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  33. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  34. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  35. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  36. // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  37. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  38. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  39. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  40. // | POSSIBILITY OF SUCH DAMAGE.                                          |
  41. // +----------------------------------------------------------------------+
  42. // | Author: Christian Dickmann <dickmann@php.net>                        |
  43. // +----------------------------------------------------------------------+
  44. //
  45. // $Id: Parser.php,v 1.30.4.1 2004/01/08 13:43:02 lsmith Exp $
  46. //
  47.  
  48. require_once('XML/Parser.php');
  49.  
  50. /**
  51.  * Parses an XML schema file
  52.  *
  53.  * @package MDB
  54.  * @category Database
  55.  * @access private
  56.  * @author  Christian Dickmann <dickmann@php.net>
  57.  */
  58. class MDB_Parser extends XML_Parser
  59. {
  60.     var $database_definition = array();
  61.     var $elements = array();
  62.     var $element '';
  63.     var $count = 0;
  64.     var $table = array();
  65.     var $table_name '';
  66.     var $field = array();
  67.     var $field_name '';
  68.     var $init = array();
  69.     var $init_name '';
  70.     var $init_value '';
  71.     var $index = array();
  72.     var $index_name '';
  73.     var $var_mode = FALSE;
  74.     var $variables = array();
  75.     var $seq = array();
  76.     var $seq_name '';
  77.     var $error = NULL;
  78.  
  79.     var $invalid_names = array(
  80.         'user' => array(),
  81.         'is' => array(),
  82.         'file' => array(
  83.             'oci' => array(),
  84.             'oracle' => array()
  85.         ),
  86.         'notify' => array(
  87.             'pgsql' => array()
  88.         ),
  89.         'restrict' => array(
  90.             'mysql' => array()
  91.         ),
  92.         'password' => array(
  93.             'ibase' => array()
  94.         )
  95.     );
  96.     var $fail_on_invalid_names = 1;
  97.  
  98.     function MDB_Parser($variables$fail_on_invalid_names = 1
  99.     {
  100.         $this->XML_Parser();
  101.         $this->variables $variables;
  102.         $this->fail_on_invalid_names $fail_on_invalid_names;
  103.     }
  104.  
  105.     function startHandler($xp$element$attribs
  106.     {   
  107.         if (strtolower($element== 'variable'{
  108.             $this->var_mode = TRUE;
  109.             return;
  110.         };
  111.         
  112.         $this->elements[$this->count++strtolower($element);
  113.         $this->element implode('-'$this->elements);
  114.         
  115.         switch($this->element{
  116.         case 'database-table-initialization-insert':
  117.             $this->init = array('type' => 'insert');
  118.             break;
  119.         case 'database-table-initialization-insert-field':
  120.             $this->init_name '';
  121.             $this->init_value '';
  122.             break;
  123.         case 'database-table':
  124.             $this->table_name '';
  125.             $this->table = array();
  126.             break;
  127.         case 'database-table-declaration-field':
  128.             $this->field_name '';
  129.             $this->field = array();
  130.             break;
  131.         case 'database-table-declaration-field-default':
  132.             $this->field['default''';
  133.             break;
  134.         case 'database-table-declaration-index':
  135.             $this->index_name '';
  136.             $this->index = array();
  137.             break;
  138.         case 'database-sequence':
  139.             $this->seq_name '';
  140.             $this->seq = array();
  141.             break;
  142.         case 'database-table-declaration-index-field':
  143.             $this->field_name '';
  144.             $this->field = array();
  145.             break;
  146.         };
  147.     }
  148.  
  149.     function endHandler($xp$element)
  150.     {
  151.         if (strtolower($element== 'variable'{
  152.             $this->var_mode = FALSE;
  153.             return;
  154.         };
  155.         
  156.         switch($this->element{
  157.         /* Initialization */
  158.         case 'database-table-initialization-insert-field':
  159.             if (!$this->init_name{
  160.                 $this->raiseError('field-name has to be specified'$xp);
  161.             };
  162.             if (isset($this->init['FIELDS'][$this->init_name])) {
  163.                 $this->raiseError('field "'.$this->init_name.'" already filled'$xp);
  164.             };
  165.             if (!isset($this->table['FIELDS'][$this->init_name])) {
  166.                 $this->raiseError('unkown field "'.$this->init_name.'"'$xp);
  167.             };
  168.             if ($this->init_value !== '' 
  169.                 && !$this->validateFieldValue($this->init_name$this->init_value$xp)) 
  170.             {
  171.                 $this->raiseError('field "'.$this->init_name.'" has wrong value'$xp);
  172.             };
  173.             $this->init['FIELDS'][$this->init_name$this->init_value;
  174.             break;
  175.         case 'database-table-initialization-insert':
  176.             $this->table['initialization'][$this->init;
  177.             break;
  178.             
  179.         /* Table definition */
  180.         case 'database-table':
  181.             if (!isset($this->table['was'])) {
  182.                 $this->table['was'$this->table_name;
  183.             };
  184.             if (!$this->table_name{
  185.                 $this->raiseError('tables need names'$xp);
  186.             };
  187.             if (isset($this->database_definition['TABLES'][$this->table_name])) {
  188.                 $this->raiseError('table "'.$this->table_name.'" already exists'$xp);
  189.             };
  190.             if (!isset($this->table['FIELDS'])) {
  191.                 $this->raiseError('tables need one or more fields'$xp);
  192.             };
  193.             if (isset($this->table['INDEXES'])) {
  194.                 foreach($this->table['INDEXES'as $index_name => $index{
  195.                     foreach($index['FIELDS'as $field_name => $field{
  196.                         if (!isset($this->table['FIELDS'][$field_name])) {
  197.                             $this->raiseError('index field "'.$field_name.'" does not exist'$xp);
  198.                         }
  199.                         if (!(isset($this->table['FIELDS'][$field_name]['notnull'])
  200.                             && $this->table['FIELDS'][$field_name]['notnull'== 1)) 
  201.                         {
  202.                             $this->raiseError('index field "'.$field_name.'" has to be "notnull"'$xp);
  203.                         }
  204.                     }
  205.                 }
  206.             };
  207.             $this->database_definition['TABLES'][$this->table_name$this->table;
  208.             break;
  209.             
  210.         /* Field declaration */
  211.         case 'database-table-declaration-field':
  212.             if (!$this->field_name || !isset($this->field['type'])) {
  213.                 $this->raiseError('field "'.$this->field_name.'" was not properly specified'$xp);
  214.             };
  215.             if (isset($this->table['FIELDS'][$this->field_name])) {
  216.                 $this->raiseError('field "'.$this->field_name.'" already exists'$xp);
  217.             };
  218.             /* Invalidname check */
  219.             if ($this->fail_on_invalid_names && isset($this->invalid_names[$this->field_name])) {
  220.                 $this->raiseError('fieldname "'.$this->field_name.'" not allowed'$xp);
  221.             };
  222.             /* Type check */
  223.             switch($this->field['type']{
  224.             case 'integer':
  225.                 if (isset($this->field['unsigned']
  226.                     && $this->field['unsigned'!== '1' && $this->field['unsigned'!== '0'
  227.                 {
  228.                     $this->raiseError('unsigned has to be 1 or 0'$xp);
  229.                 };
  230.                 break;
  231.             case 'text':
  232.             case 'clob':
  233.             case 'blob':
  234.                 if (isset($this->field['length']&& ((int)$this->field['length']<= 0{
  235.                     $this->raiseError('length has to be an integer greater 0'$xp);
  236.                 };
  237.                 break;
  238.             case 'boolean':
  239.             case 'date':
  240.             case 'timestamp':
  241.             case 'time':
  242.             case 'float':
  243.             case 'decimal':
  244.                 break;
  245.             default: 
  246.                 $this->raiseError('no valid field type ("'.$this->field['type'].'") specified'$xp);
  247.             };
  248.             if (!isset($this->field['was'])) {
  249.                 $this->field['was'$this->field_name;
  250.             };
  251.             if (isset($this->field['notnull']&& !$this->is_boolean($this->field['notnull'])) {
  252.                 $this->raiseError('field  "notnull" has to be 1 or 0'$xp);
  253.             };
  254.             if (isset($this->field['notnull']&& !isset($this->field['default'])) {
  255.                 $this->raiseError('if field is "notnull", it needs a default value'$xp);
  256.             };
  257.             if (isset($this->field['unsigned']&& !$this->is_boolean($this->field['unsigned'])) {
  258.                 $this->raiseError('field  "notnull" has to be 1 or 0'$xp);
  259.             };
  260.             $this->table['FIELDS'][$this->field_name$this->field;
  261.             if (isset($this->field['default'])) {
  262.                 if ($this->field['type'== 'clob' || $this->field['type'== 'blob'{
  263.                     $this->raiseError('"'.$this->field['type'].'"-fields are not allowed to have a default value'$xp);
  264.                 };
  265.                 if ($this->field['default'!== '' 
  266.                     && !$this->validateFieldValue($this->field_name$this->field['default']$xp))
  267.                 {
  268.                     $this->raiseError('default value of "'.$this->field_name.'" is of wrong type'$xp);
  269.                 };
  270.             };
  271.             break;
  272.             
  273.         /* Index declaration */
  274.         case 'database-table-declaration-index':
  275.             if (!$this->index_name{
  276.                 $this->raiseError('an index needs a name'$xp);
  277.             };
  278.             if (isset($this->table['INDEXES'][$this->index_name])) {
  279.                 $this->raiseError('index "'.$this->index_name.'" already exists'$xp);
  280.             };
  281.             if (isset($this->index['unique']&& !$this->is_boolean($this->index['unique'])) {
  282.                 $this->raiseError('field  "unique" has to be 1 or 0'$xp);
  283.             };
  284.             if (!isset($this->index['was'])) {
  285.                 $this->index['was'$this->index_name;
  286.             };
  287.             $this->table['INDEXES'][$this->index_name$this->index;
  288.             break;
  289.         case 'database-table-declaration-index-field':
  290.             if (!$this->field_name{
  291.                 $this->raiseError('the index-field-name is required'$xp);
  292.             };
  293.             if (isset($this->field['sorting']
  294.                 && $this->field['sorting'!== 'ascending' && $this->field['sorting'!== 'descending'{
  295.                 $this->raiseError('sorting type unknown'$xp);
  296.             };
  297.             $this->index['FIELDS'][$this->field_name$this->field;
  298.             break;
  299.             
  300.         /* Sequence declaration */
  301.         case 'database-sequence':
  302.             if (!$this->seq_name{
  303.                 $this->raiseError('a sequence has to have a name'$xp);
  304.             };
  305.             if (isset($this->database_definition['SEQUENCES'][$this->seq_name])) {
  306.                 $this->raiseError('sequence "'.$this->seq_name.'" already exists'$xp);
  307.             };
  308.             if (!isset($this->seq['was'])) {
  309.                 $this->seq['was'$this->seq_name;
  310.             };
  311.             if (isset($this->seq['on'])) {
  312.                 if ((!isset($this->seq['on']['table']|| !$this->seq['on']['table'])
  313.                     || (!isset($this->seq['on']['field']|| !$this->seq['on']['field'])) 
  314.                 {
  315.                     $this->raiseError('sequence "'.$this->seq_name.'" was not properly defined'$xp);
  316.                 };
  317.             };
  318.             $this->database_definition['SEQUENCES'][$this->seq_name$this->seq;
  319.             break;
  320.             
  321.         /* End of File */
  322.         case 'database':
  323.             if (isset($this->database_definition['create']
  324.                 && !$this->is_boolean($this->database_definition['create']))
  325.             {
  326.                 $this->raiseError('field "create" has to be 1 or 0'$xp);
  327.             };
  328.             if (isset($this->database_definition['overwrite']
  329.                 && !$this->is_boolean($this->database_definition['overwrite']))
  330.             {
  331.                 $this->raiseError('field "overwrite" has to be 1 or 0'$xp);
  332.             };
  333.             if (!isset($this->database_definition['name']|| !$this->database_definition['name']{
  334.                 $this->raiseError('database needs a name'$xp);
  335.             };
  336.             if (isset($this->database_definition['SEQUENCES'])) {
  337.                 foreach($this->database_definition['SEQUENCES'as $seq_name => $seq{
  338.                     if (isset($seq['on']
  339.                         && !isset($this->database_definition['TABLES'][$seq['on']['table']]['FIELDS'][$seq['on']['field']]))
  340.                     {
  341.                         $this->raiseError('sequence "'.$seq_name.'" was assigned on unexisting field/table'$xp);
  342.                     };
  343.                 };
  344.             };
  345.             if (MDB::isError($this->error)) {
  346.                 $this->database_definition $this->error;
  347.             };
  348.             break;
  349.         }
  350.         
  351.         unset($this->elements[--$this->count]);
  352.         $this->element implode('-'$this->elements);
  353.     }
  354.  
  355.     function validateFieldValue($field_name&$field_value&$xp)
  356.     {
  357.         if (!isset($this->table['FIELDS'][$field_name])) {
  358.             return;
  359.         };
  360.         $field_def $this->table['FIELDS'][$field_name];
  361.         switch($field_def['type']{
  362.         case 'text':
  363.         case 'clob':
  364.             if (isset($field_def['length']&& strlen($field_value$field_def['length']{
  365.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  366.             };
  367.             break;
  368.         case 'blob':
  369.             /*
  370.             if (!preg_match('/^([0-9a-f]{2})*$/i', $field_value)) {
  371.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"', $xp));
  372.             }
  373.             */
  374.             $field_value pack('H*'$field_value);
  375.             if (isset($field_def['length']&& strlen($field_value$field_def['length']{
  376.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  377.             };
  378.             break;
  379.         case 'integer':
  380.             if ($field_value != ((int)$field_value)) {
  381.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  382.             };
  383.             $field_value = (int) $field_value;
  384.             if (isset($field_def['unsigned']&& $field_def['unsigned'&& $field_value < 0{
  385.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  386.             };
  387.             break;
  388.         case 'boolean':
  389.             if (!$this->is_boolean($field_value)) {
  390.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  391.             }
  392.             break;
  393.         case 'date':
  394.             if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/'$field_value)) {
  395.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  396.             }
  397.             break;
  398.         case 'timestamp':
  399.             if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/'$field_value)) {
  400.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  401.             }
  402.             break;
  403.         case 'time':
  404.             if (!preg_match("/([0-9]{2}):([0-9]{2}):([0-9]{2})/"$field_value)) {
  405.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  406.             }
  407.             break;
  408.         case 'float':
  409.         case 'double':
  410.             if ($field_value != (double) $field_value{
  411.                 return($this->raiseError('"'.$field_value.'" is not of type "'.$field_def['type'].'"'$xp));
  412.             };
  413.             $field_value = (double) $field_value;
  414.             break;
  415.         }
  416.         return(TRUE);
  417.     }
  418.  
  419.     function raiseError($msg$xp = NULL)
  420.     {
  421.         if ($this->error === NULL{
  422.             if(is_resource($msg)) {
  423.                 $error "Parser error: ";
  424.                 $xp $msg;
  425.             else {
  426.                 $error "Parser error: \"".$msg."\"\n";
  427.             }
  428.             if($xp != NULL{
  429.                 $byte @xml_get_current_byte_index($xp);
  430.                 $line @xml_get_current_line_number($xp);
  431.                 $column @xml_get_current_column_number($xp);
  432.                 $error .= "Byte: $byte; Line: $line; Col: $column\n";
  433.             }
  434.             $this->error = PEAR::raiseError(NULLMDB_ERROR_MANAGER_PARSENULLNULL,
  435.                 $error'MDB_Error'TRUE);
  436.         };
  437.         return(FALSE);
  438.     }
  439.  
  440.     function is_boolean(&$value)
  441.     {
  442.         if (is_int($value&& ($value == 0 || $value == 1)) {
  443.             return(TRUE);
  444.         };
  445.         if ($value === '1' || $value === '0'{
  446.             $value = (int) $value;
  447.             return(TRUE);
  448.         };
  449.         switch($value)
  450.         {
  451.         case 'N':
  452.         case 'n':
  453.         case 'no':
  454.         case 'FALSE':
  455.             $value = 0;
  456.             break;
  457.         case 'Y':
  458.         case 'y':
  459.         case 'yes':
  460.         case 'TRUE':
  461.             $value = 1;
  462.             break;
  463.         default:
  464.             return(FALSE);
  465.         };
  466.         return(TRUE);
  467.     }
  468.  
  469.     function cdataHandler($xp$data)
  470.     {
  471.         if ($this->var_mode == TRUE{
  472.             if (!isset($this->variables[$data])) {
  473.                 $this->raiseError('variable "'.$data.'" not found'$xp);
  474.                 return;
  475.             };
  476.             $data $this->variables[$data];
  477.         };
  478.         
  479.         switch($this->element{
  480.         /* Initialization */
  481.         case 'database-table-initialization-insert-field-name':
  482.             @$this->init_name .= $data;
  483.             break;
  484.         case 'database-table-initialization-insert-field-value':
  485.             @$this->init_value .= $data;
  486.             break;
  487.             
  488.         /* Database */
  489.         case 'database-name'
  490.             @$this->database_definition['name'.= $data;
  491.             break;
  492.         case 'database-create':
  493.             @$this->database_definition['create'.= $data;
  494.             break;
  495.         case 'database-overwrite':
  496.             @$this->database_definition['overwrite'.= $data;
  497.             break;
  498.         case 'database-table-name':
  499.             @$this->table_name .= $data;
  500.             break;
  501.         case 'database-table-was':
  502.             @$this->table['was'.= $data;
  503.             break;
  504.             
  505.         /* Field declaration */
  506.         case 'database-table-declaration-field-name':
  507.             @$this->field_name .= $data;
  508.             break;
  509.         case 'database-table-declaration-field-type':
  510.             @$this->field['type'.= $data;
  511.             break;
  512.         case 'database-table-declaration-field-was':
  513.             @$this->field['was'.= $data;
  514.             break;
  515.         case 'database-table-declaration-field-notnull':
  516.             @$this->field['notnull'.= $data;
  517.             break;
  518.         case 'database-table-declaration-field-unsigned':
  519.             @$this->field['unsigned'.= $data;
  520.             break;
  521.         case 'database-table-declaration-field-default':
  522.             @$this->field['default'.= $data;
  523.             break;
  524.         case 'database-table-declaration-field-length':
  525.             @$this->field['length'.= $data;
  526.             break;
  527.             
  528.         /* Index declaration */
  529.         case 'database-table-declaration-index-name':
  530.             @$this->index_name .= $data;
  531.             break;
  532.         case 'database-table-declaration-index-unique':
  533.             @$this->index['unique'.= $data;
  534.             break;
  535.         case 'database-table-declaration-index-was':
  536.             @$this->index['was'.= $data;
  537.             break;
  538.         case 'database-table-declaration-index-field-name':
  539.             @$this->field_name .= $data;
  540.             break;
  541.         case 'database-table-declaration-index-field-sorting':
  542.             @$this->field['sorting'.= $data;
  543.             break;
  544.             
  545.         /* Sequence declaration */
  546.         case 'database-sequence-name':
  547.             @$this->seq_name .= $data;
  548.             break;
  549.         case 'database-sequence-was':
  550.             @$this->seq['was'.= $data;
  551.             break;
  552.         case 'database-sequence-start':
  553.             @$this->seq['start'.= $data;
  554.             break;
  555.         case 'database-sequence-on-table':
  556.             @$this->seq['on']['table'.= $data;
  557.             break;
  558.         case 'database-sequence-on-field':
  559.             @$this->seq['on']['field'.= $data;
  560.             break;
  561.         };
  562.     }
  563. };
  564.  
  565. ?>

Documentation generated on Mon, 11 Mar 2019 10:15:30 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.