views:

262

answers:

5

Hi Guys, Consider these three mysql statements:

select * from Users;
select id, title, value from Blogs;
select id, feelURL, feelTitle from Feeds where id = 1; 

Now im not very good at REGEX, but i want to get the table name from the mysql query. Could someone possibly create one for me with a little explanation.

Thanks,

A: 

For the query string you gave, the following should do:

preg_match_all('/from (\w+)/', $query, $tables);

print_r($tables[1]);

[0] => Users
[1] => Blogs
[2] => Feeds

But like pointed out in a comment already, creating a full fledged SQL parser is a non-trivial task. Don't expect this to be usable on any and all queries you throw against it.

Gordon
+1  A: 

Try:

preg_match('/\bfrom\b\s*(\w+)/i',$query,$matches)

This will not work if the query has more than 1 table.

Basically the regex searchs for the complete word FROM in the query and picks the following word as the table name.

codaddict
A: 

A naive implementation would be this:

preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);

echo $query . " => " . $match[1] . "\n";

This will break when you have a subquery in your SELECT field list (and probably in a few other cases). Or when your table name contains characters beside a-z, numbers and underscores.

Parsing SQL correctly isn't trivial.

Alexander Malfait
A: 

not sure what your trying to accomplish but would this be more useful ? mysql_tablename

mcgrailm
A: 

Wish I would have seen this earlier... Like the people above me stated, it's non-trivial parsing sql statements. To pick out the table names from a sql string, it would be a better idea to get all the table names first, then find matches in the sql (providing you don't have a million tables in your database). I just so happen to have a function on hand that does just that:

/*
  Takes a sql statement and attempts to get a table name from it.
  This assumes a database is already specified in the connection.

  [$sql]: string; SQL statement that was executed
  [$conn]: resource; MySQLi connection resource

  returns table name string
 */  
function get_table_names($sql,$conn){
    //declare variables
    $table_array = array();
    $table_string = "";

    //get all the table names in the selected database
    $sql2 = "SHOW TABLES";
    $result = mysqli_query($conn, $sql2);

    //display an error if something went wrong
    if (!$result) {
        echo "DB Error, could not list tables\n";
        echo 'MySQL Error: ' . mysqli_error($conn);
        exit;
    }

    //fetch the rows and push the table names into $table_array
    while ($row = mysqli_fetch_row($result)) {
        array_push($table_array, $row[0]);
    }

    //loop through all the tables in the database
    foreach($table_array as $table){
        if(strpos($sql,$table)){ //if match is found append to string
            $table_string .= " $table ";
        }
    }

    //return a string of table name matches
    return $table_string;
}

Hope that helps someone...

Troy Knapp
Return false positive is `table_name' is part of a value (ie: SELECT * FROM myTable WHERE column='foo bar anotherTable';)
M42
Yes you're right, but it handles multiple tables that would break the other regex's. In my experience, it's a lot more likely to have select statements spanning across multiple tables than it is to name another table in a column. So yes, not perfect, but IMO, better.
Troy Knapp
Btw, I tried writing a regex as well, and you have to account for all the ways that MySQL will accept an insertion for example all these work (this is a problem with tolerant languages):FROM \`foo\`.\`bar\` WHERE FROM \`bar\` WHERE FROM\`foo\`.\`bar\` WHERE FROM \`foo\` .\`bar\` WHERE FROM foo.bar WHERE FROM bar WHERE ... (there is a huge amount of permutations possible)and the syntax changes with insert statements, delete statements etc. None of the regex's on here can deal with all of the above cases.
Troy Knapp