Projekt

Obecné

Profil

Stáhnout (4.21 KB) Statistiky
| Větev: | Tag: | Revize:
18ac9009 Ondřej Fibich
<?php

/*
* This file is part of open source system FreenetIS
* and it is release under GPLv3 licence.
*
* More info about licence can be found:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* More info about project can be found:
* http://www.freenetis.org/
*/

/**
* SQL script file parser for parsing of SQL queries passed as single string
* delimited by semicolons. Comment are started using "--".
*
* @author Ondřej Fibich <fibich@freenetis.org>
* @since 1.2
*/
class SqlScriptParser
{
// states for finite automata that is used for parsing

/** In query state */
const STATE_QUERY = 0;
/** In query string state */
const STATE_STRING = 2;
/** In query string escaped character state */
const STATE_STRING_ESCAPE = 3;
/** In maybe comment state */
const STATE_COMMENT_START = 4;
/** In comment state */
const STATE_COMMENT = 5;

/**
* Parse SQL queries that must be ended by semicolons.
*
* @param string $script_content SQL script file content
* @return array parsed queries, each query is trimed for white spaces
* @throws InvalidArgumentException on invalid script content
*/
public function parse_queries($script_content)
{
if (!is_string($script_content) || empty($script_content))
{
return array();
}

$s = self::STATE_QUERY; // FA status
$queries = array(); // parsed queries (result)
$buffer = array(); // help letter buffer
$string_term = NULL; // last string termination character (" or ')
$script_content_char_array = str_split($script_content);
$script_length = count($script_content_char_array);

for ($i = 0; $i < $script_length; $i++)
{
$letter = $script_content_char_array[$i];

switch ($s)
{
case self::STATE_QUERY:
case self::STATE_COMMENT_START:
$s = $this->fa_in_query($s, $letter, $buffer, $queries,
$string_term);
break;
case self::STATE_STRING:
$s = $this->fa_in_string($letter, $buffer, $string_term);
break;
case self::STATE_STRING_ESCAPE:
$buffer[] = $letter;
$s = self::STATE_STRING; // only one letter after \
break;
case self::STATE_COMMENT:
$s = $this->fa_in_comment($letter);
break;
default:
throw new Exception('Unhandled FA status: ' . $s);
}
}

return $queries;
}

private function fa_in_query($status, $letter, array &$buffer,
array &$queries, &$string_term)
{
switch ($letter)
{
case '-':
if ($status === self::STATE_COMMENT_START)
{
array_pop($buffer); // remove -
return self::STATE_COMMENT;
}
$buffer[] = $letter;
return self::STATE_COMMENT_START;
case '"':
case '\'':
$buffer[] = $letter;
$string_term = $letter;
return self::STATE_STRING;
case ';': // query end
if (empty($buffer))
{
throw new InvalidArgumentException('empty SQL query parsed');
}
$queries[] = trim(implode('', $buffer));
$buffer = array();
return self::STATE_QUERY;
default:
$buffer[] = $letter;
return $status;
}
}

private function fa_in_string($letter, array &$buffer, &$string_term)
{
$buffer[] = $letter;

switch ($letter)
{
case '\\':
return self::STATE_STRING_ESCAPE;
case $string_term:
$string_term = NULL;
return self::STATE_QUERY;
default:
return self::STATE_STRING;
}
}

private function fa_in_comment($letter)
{
return ($letter === "\n") ? self::STATE_QUERY : self::STATE_COMMENT;
}

}