How can I get enum possible values in a MySQL database? - php

I want to populate my dropdowns with enum possible values from a DB automatically. Is this possible in MySQL?

I have a codeigniter version for you. It also strips the quotes from the values.
function get_enum_values( $table, $field )
{
$type = $this->db->query( "SHOW COLUMNS FROM {$table} WHERE Field = '{$field}'" )->row( 0 )->Type;
preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
$enum = explode("','", $matches[1]);
return $enum;
}

You can get the values by querying it like this:
SELECT SUBSTRING(COLUMN_TYPE,5)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='databasename'
AND TABLE_NAME='tablename'
AND COLUMN_NAME='columnname'
From there you'll need to convert it into an array:
eval that directly into an array if you're lazy (although MySQL's single quote escape might be incompatible), or
$options_array = str_getcsv($options, ',', "'") possibly would work (if you alter the substring to skip the opening and closing parentheses), or
a regular expression

MySQL Reference
If you want to determine all possible
values for an ENUM column, use SHOW
COLUMNS FROM tbl_name LIKE enum_col
and parse the ENUM definition in the
Type column of the output.
You would want something like:
$sql = "SHOW COLUMNS FROM `table` LIKE 'column'";
$result = $db->query($sql);
$row = $result->fetchRow();
$type = $row['Type'];
preg_match('/enum\((.*)\)$/', $type, $matches);
$vals = explode(',', $matches[1]);
This will give you the quoted values. MySQL always returns these enclosed in single quotes. A single quote in the value is escaped by a single quote. You can probably safely call trim($val, "'") on each of the array elements. You'll want to convert '' into just '.
The following will return $trimmedvals array items without quotes:
$trimmedvals = array();
foreach($vals as $key => $value) {
$value=trim($value, "'");
$trimmedvals[] = $value;
}

This is like a lot of the above, but gives you the result without loops, AND gets you want you really want: a simple array for generating select options.
BONUS: It works for SET as well as ENUM field types.
$result = $db->query("SHOW COLUMNS FROM table LIKE 'column'");
if ($result) {
$option_array = explode("','",preg_replace("/(enum|set)\('(.+?)'\)/","\\2", $result[0]->Type));
}
$option_array:
Array
(
[0] => red
[1] => green
[2] => blue
)

You can parse the string as though it was a CSV (Comma Separated Value) string. PHP has a great build-in function called str_getcsv which converts a CSV string to an array.
// This is an example to test with
$enum_or_set = "'blond','brunette','redhead'";
// Here is the parser
$options = str_getcsv($enum_or_set, ',', "'");
// Output the value
print_r($options);
This should give you something similar to the following:
Array
(
[0] => blond
[1] => brunette
[2] => redhead
)
This method also allows you to have single quotes in your strings (notice the use of two single quotes):
$enum_or_set = "'blond','brunette','red''head'";
Array
(
[0] => blond
[1] => brunette
[2] => red'head
)
For more information on the str_getcsv function, check the PHP manual:
http://uk.php.net/manual/en/function.str-getcsv.php

This is one of Chris Komlenic's 8 Reasons Why MySQL's ENUM Data Type Is Evil:
4. Getting a list of distinct ENUM members is a pain.
A very common need is to populate a select-box or drop down list with possible values from the database. Like this:
Select color:
[ select box ]
If these values are stored in a reference table named 'colors', all you need is: SELECT * FROM colors ...which can then be parsed out to dynamically generate the drop down list. You can add or change the colors in the reference table, and your sexy order forms will automatically be updated. Awesome.
Now consider the evil ENUM: how do you extract the member list? You could query the ENUM column in your table for DISTINCT values but that will only return values that are actually used and present in the table, not necessarily all possible values. You can query INFORMATION_SCHEMA and parse them out of the query result with a scripting language, but that's unnecessarily complicated. In fact, I don't know of any elegant, purely SQL way to extract the member list of an ENUM column.

A more up to date way of doing it, this worked for me:
function enum_to_array($table, $field) {
$query = "SHOW FIELDS FROM `{$table}` LIKE '{$field}'";
$result = $db->query($sql);
$row = $result->fetchRow();
preg_match('#^enum\((.*?)\)$#ism', $row['Type'], $matches);
$enum = str_getcsv($matches[1], ",", "'");
return $enum;
}
Ultimately, the enum values when separated from "enum()" is just a CSV string, so parse it as such!

here is for mysqli
function get_enum_values($mysqli, $table, $field )
{
$type = $mysqli->query("SHOW COLUMNS FROM {$table} WHERE Field = '{$field}'")->fetch_array(MYSQLI_ASSOC)['Type'];
preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
$enum = explode("','", $matches[1]);
return $enum;
}
$deltypevals = get_enum_values($mysqli, 'orders', 'deltype');
var_dump ($deltypevals);

Here is the same function given by Patrick Savalle adapted for the framework Laravel
function get_enum_values($table, $field)
{
$test=DB::select(DB::raw("show columns from {$table} where field = '{$field}'"));
preg_match('/^enum\((.*)\)$/', $test[0]->Type, $matches);
foreach( explode(',', $matches[1]) as $value )
{
$enum[] = trim( $value, "'" );
}
return $enum;
}

To fetch the list of possible values has been well documented, but expanding on another answer that returned the values in parenthesis, I wanted to strip them out leaving me with a comma separated list that would then allow me to use an explode type function whenever I needed to get an array.
SELECT
SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6) AS val
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = 'articles'
AND
COLUMN_NAME = 'status'
The SUBSTRING now starts at the 6th character and uses a length which is 6 characters shorter than the total, removing the trailing parenthesis.

I simply want to add to what jasonbar says, when querying like:
SHOW columns FROM table
If you get the result out as an array it will look like this:
array([0],[Field],[1],[Type],[2],[Null],[3],[Key],[4],[Default],[5],[Extra])
Where [n] and [text] give the same value.
Not really told in any documentation I have found. Simply good to know what else is there.

All of you use some strange and complex regex patterns x)
Here's my solution without preg_match :
function getEnumTypes($table, $field) {
$query = $this->db->prepare("SHOW COLUMNS FROM $table WHERE Field = ?");
try {$query->execute(array($field));} catch (Exception $e) {error_log($e->getMessage());}
$types = $query->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE, 1)[$field];
return explode("','", trim($types, "enum()'"));
}

For Laravel this worked:
$result = DB::select("SHOW COLUMNS FROM `table_name` LIKE 'status';");
$regex = "/'(.*?)'/";
preg_match_all( $regex , $result[0]->Type, $enum_array );
$enum_fields = $enum_array[1];
echo "<pre>";
print_r($enum_fields);
Output:
Array
(
[0] => Requested
[1] => Call Back
[2] => Busy
[3] => Not Reachable
[4] => Not Responding
)

The problem with every other answer in this thread is that none of them properly parse all special cases of the strings within the enum.
The biggest special case character that was throwing me for a loop was single quotes, as they are encoded themselves as 2 single quotes together! So, for example, an enum with the value 'a' is encoded as enum('''a'''). Horrible, right?
Well, the solution is to use MySQL to parse the data for you!
Since everyone else is using PHP in this thread, that is what I will use. Following is the full code. I will explain it after. The parameter $FullEnumString will hold the entire enum string, extracted from whatever method you want to use from all the other answers. RunQuery() and FetchRow() (non associative) are stand ins for your favorite DB access methods.
function GetDataFromEnum($FullEnumString)
{
if(!preg_match('/^enum\((.*)\)$/iD', $FullEnumString, $Matches))
return null;
return FetchRow(RunQuery('SELECT '.$Matches[1]));
}
preg_match('/^enum\((.*)\)$/iD', $FullEnumString, $Matches) confirms that the enum value matches what we expect, which is to say, "enum(".$STUFF.")" (with nothing before or after). If the preg_match fails, NULL is returned.
This preg_match also stores the list of strings, escaped in weird SQL syntax, in $Matches[1]. So next, we want to be able to get the real data out of that. So you just run "SELECT ".$Matches[1], and you have a full list of the strings in your first record!
So just pull out that record with a FetchRow(RunQuery(...)) and you’re done.
If you wanted to do this entire thing in SQL, you could use the following
SET #TableName='your_table_name', #ColName='your_col_name', #DBName='your_database_name';
SET #Q=(SELECT CONCAT('SELECT ', (SELECT SUBSTR(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE)-6) FROM information_schema.COLUMNS WHERE TABLE_NAME=#TableName AND COLUMN_NAME=#ColName AND TABLE_SCHEMA=#DBName)));
PREPARE stmt FROM #Q;
EXECUTE stmt;
P.S. To preempt anyone from saying something about it, no, I do not believe this method can lead to SQL injection.

$row = db_fetch_object($result);
if($row){
$type = $row->Type;
preg_match_all("/'([^']+)'/", $type, $matches,PREG_PATTERN_ORDER );
return $matches[1];
}

try this
describe table columnname
gives you all the information about that column in that table;

Codeigniter adapting version as method of some model:
public function enum_values($table_name, $field_name)
{
$query = $this->db->query("SHOW COLUMNS FROM `{$table_name}` LIKE '{$field_name}'");
if(!$query->num_rows()) return array();
preg_match_all('~\'([^\']*)\'~', $query->row('Type'), $matches);
return $matches[1];
}
Result:
array(2) {
[0]=> string(13) "administrator"
[1]=> string(8) "customer"
}

this will work for me:
SELECT REPLACE(SUBSTRING(COLUMN_TYPE,6,(LENGTH(COLUMN_TYPE)-6)),"'","")
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='__TABLE_SCHEMA__'
AND TABLE_NAME='__TABLE_NAME__'
AND COLUMN_NAME='__COLUMN_NAME__'
and then
explode(',', $data)

You can use this syntax for get enum possible values in MySQL QUERY :
$syntax = "SELECT COLUMN_TYPY FROM information_schema.`COLUMNS`
WHERE TABLE_NAME = '{$THE_TABLE_NAME}'
AND COLUMN_NAME = '{$THE_COLUMN_OF_TABLE}'";
and you get value, example : enum('Male','Female')
this is example sytax php:
<?php
function ($table,$colm){
// mysql query.
$syntax = mysql_query("SELECT COLUMN_TYPY FROM information_schema.`COLUMNS`
WHERE TABLE_NAME = '$table' AND COLUMN_NAME ='$colm'");
if (!mysql_error()){
//Get a array possible values from table and colm.
$array_string = mysql_fetch_array($syntax);
//Remove part string
$string = str_replace("'", "", $array_string['COLUMN_TYPE']);
$string = str_replace(')', "", $string);
$string = explode(",",substr(5,$string));
}else{
$string = "error mysql :".mysql_error();
}
// Values is (Examples) Male,Female,Other
return $string;
}
?>

I get enum values in this way:
SELECT COLUMN_TYPE
FROM information_schema.`COLUMNS`
WHERE TABLE_NAME = 'tableName'
AND COLUMN_NAME = 'columnName';
Running this sql I have get : enum('BDBL','AB Bank')
then I have filtered just value using following code :
preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
$enum = explode("','", $matches[1]);
var_dump($enum) ;
Out put :
array(2) {
[0]=>
string(4) "BDBL"
[1]=>
string(7) "AB Bank"
}

just for fun, i wrote a FSM solution which is UTF-8 safe and quote-resistant.
I assumed that mysql/mariadb always uses single quotes to wrap values and doubles the quote for a literal ' .
$string=$column_info;
$char = '';
$next_char = '';
$buffer = '';
$buffering = false;
$enum_values = array();
while( mb_strlen($string) > 0 ){
// consume a multibyte char
$char=mb_substr($string,0,1);
$string=mb_substr($string,1);
if ( $char === "'" && $buffering === false ) {
// start buffering
$buffering=true;
} else if ( $char === "'" && $buffering === true){
// see next char
$next_char=mb_substr($string,0,1);
$string=mb_substr($string,1);
if( $next_char === "'" ){
// two quote '' found, literal
$buffer = "$buffer$char";
} else {
// end of string
$enum_values[] = $buffer;
$buffer = '';
$buffering = false;
}
} else if( $buffering === true ) {
// normal char during buffering
$buffer = "$buffer$char";
}
}
if( $buffering ){
// this means an unterminated string
throw new \Exception("Unterminated string in enum");
}
return $enum_values;
tested against:
array(7) {
[0]=>
string(10) "added enum"
[1]=>
string(22) "a "double Quoted" enum"
[2]=>
string(6) "normal"
[3]=>
string(26) "an utf-8 enum ☠ (middle)"
[4]=>
string(15) "a 'Quoted' enum"
[5]=>
string(21) "a single quote ' enum"
[6]=>
string(23) "an utf-8 enum (end) ☠"
}

For PHP 5.6+
$mysqli = new mysqli("example.com","username","password","database");
$result = $mysqli->query("SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='table_name' AND COLUMN_NAME='column_name'");
$row = $result->fetch_assoc();
var_dump($row);

DELIMITER //
DROP FUNCTION IF EXISTS ENUM_VALUES;
CREATE FUNCTION ENUM_VALUES(
_table_name VARCHAR(64),
_col_name VARCHAR(64)
) RETURNS JSON
BEGIN
RETURN (
SELECT CAST(CONCAT('[', REPLACE(SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6), "'", '"'), ']') AS JSON)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'db_name'
AND TABLE_NAME = _table_name
AND COLUMN_NAME = _col_name
AND DATA_TYPE = 'enum'
);
END //
DELIMITER ;
Example:
SELECT ENUM_VALUES('table_name', 'col_name');

For Yii framework there is little change with:
function getEnumValues($table, $field)
{
$stmt = " SHOW COLUMNS FROM {{{$table}}} WHERE Field = '$field'";
$type = Yii::app()->db->createCommand($stmt)->queryRow()["Type"];
preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
return explode("','", $matches[1]);
}

It is extraordinary how none of you has thought that if you are using an enum field it means that the values to be assigned are known "a priori".
Therefore if the values are known "a priori" the best ways to manage them is through a very simple Enum class.
Kiss rule and save one database call.
<?php
class Genre extends \SplEnum {
const male = "Male";
const female = "Female";
}
http://it2.php.net/manual/en/class.splenum.php

Here is a solution for a custom WordPress table. This will work for ENUM values without a comma (,) in them
function get_enum_values($wpdb, $table, $field) {
$values = array();
$table = "{$wpdb->prefix}{$table}";
$query = "SHOW COLUMNS FROM {$table} WHERE Field = '{$field}'";
$results = $wpdb->get_results($query, ARRAY_A);
if (is_array($results) && count($results) > 0) {
preg_match("/^enum\(\'(.*)\'\)$/", $results[0]['Type'], $matches);
if (is_array($matches) && isset($matches[1])) {
$values = explode("','", $matches[1]);
}
}
return $values;
}

Adding to cchana's answer. The method "length-6" fails on non-latin values in enum.
For example (the values are in Cyrillic, table is UTF8 - utf8_general_ci. In the examples I use the variable for simplicity: selecting from schema gives the same):
set #a:="enum('в работе','на списание','списано')";
select substring(#a,6,length(#a)-6);
+-------------------------------------------------------------+
| substring(#a,6,length(#a)-6) |
+-------------------------------------------------------------+
| 'в работе','на списание','списано') |
+-------------------------------------------------------------+
Note the closing parenthesis?
select right(#a,1);
+-------------+
| right(#a,1) |
+-------------+
| ) |
+-------------+
Well, let's try remove one more character:
select substring(#a,6,length(#a)-7);
+-------------------------------------------------------------+
| substring(#a,6,length(#a)-7) |
+-------------------------------------------------------------+
| 'в работе','на списание','списано') |
+-------------------------------------------------------------+
No luck! The parenthesis stays in place.
Checking (mid() function works in way similar to substring(), and both shows the same results):
select mid(#a,6,length(#a)/2);
+---------------------------------------------------------+
| mid(#a,6,length(#a)/2) |
+---------------------------------------------------------+
| 'в работе','на списание','списан |
+---------------------------------------------------------+
See: the string lost only three rightmost characters. But should we replace Cyrillic with Latin, and all works just perfectly:
set #b:="enum('in use','for removal','trashed')";
select (substring(#b,6,length(#b)-6));
+----------------------------------+
| (substring(#b,6,length(#b)-6)) |
+----------------------------------+
| 'in use','for removal','trashed' |
+----------------------------------+
JFYI
Edit 20210221: the solution for non-Latin characters is CHAR_LENGTH() instead of "simple" LENGTH()

This will work using PDO:
$stmt = $mysql->prepare("SHOW COLUMNS FROM table LIKE 'column'");
$stmt->execute();
$enumvalues = $stmt->fetch(PDO::FETCH_ASSOC)['Type'];
$enumvalues = explode(',', str_replace('\'', '', substr($enumvalues, 5, strlen($enumvalues) - 6)));

SELECT
SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6) AS val
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = 'articles'
AND
COLUMN_NAME = 'status'
Wouldn't work for enum('','X''XX')

Related

how can i replace every single character with a "?" mark in a string with php

so for example i gave this string
sbbibs
with php i would like to change it to
??????
my query currently is this, i cant continute yet cus the ? marks
namespace modules\xenforums\sql;
trait create_row {
function create_row($types, $table, $column, $param, $conn) {
$param = "'" . implode ( "', '", $param ) . "'";
$placeholders = str_split($types);
$a = str_replace(); // this is where i want to make every type to ?
// posible value of $type, sssissb
$query = "INSERT INTO {$table} ({$column}) VALUES ({$placeholders})";
var_dump($a);
}
}
how could i do so?
im doing this because i made a php mysqli query builder and now i'm trying to replace the data types with ? to get the amount of given parameter
iv tried using str_replaces but that only does 1 specific
i also had the idea of doing str_replace for every char, but that's too tedious
iv also thought about just doing it for the current data types, but for other data base systems thats not all the same
When you want to make a string unreadable by replacing every character with a question mark you can just:
Get the length of your current string
And create a new string which puts the amount of characters in as a question mark by using a for loop.
the result would be something like that:
$input = "Test";
$output = "";
for ($i =0 ; $i < strlen(input) ; $i++) {
$output .= "?";
}
One line code for this:
str_pad('', strlen($string), '?');
Or better yet:
str_repeat('?', strlen($string));

Update All Values in MySQL Column to Follow Pattern

I have a column in a table of a MySQL database that stores numbers separated by commas. Here's an example:
,,322,,,,455,,,,698,,,,722,
There is a specific pattern:
The first number always has two commas before it
The numbers in between the first and last are separated by 4 commas
The last number is followed by a single comma
The numbers are ALWAYS separated by commas
I'm having some difficulty maintaining this pattern.. sometimes this field updates incorrectly resulting in too many or too few commas in certain places like so:
,,166,,,,845,,,,,,,,846,
I use this PHP to add/remove commas:
public function serializeArray($array) {
$string = ',';
foreach ($array as $obj) {
$string .= ',' . $obj . ',';
}
return $string;
}
public function unserializeArray($string) {
$array = explode(",,",$string);
unset($array[0]);
$array = array_values($array);
return $array;
echo "Array: " . print_r($array);
}
SQL to update column:
$query = $this->pdo->prepare(
'UPDATE `' . $this->table . '` SET
`team_ids` = :team_ids
WHERE `id` = :customer_id LIMIT 1;');
$query->bindParam(':customer_id', $customer_id, PDO::PARAM_INT);
$query->bindParam(':team_ids', $team_ids);
$query->execute();
What SQL can I use to UPDATE all of the values in the column to follow the specific pattern requirements mentioned above?
The issue here looks like you're missing a number, not that it is not following your pattern.
,,166,,,,845,,,,Missing No,,,,846,
Are you sure you want to delete this? I would instead focus on catching the null or blank number.
If so, it looks like you should be able to do a replace
Update TableName
Set NumberPattern = Replace(NumberPattern, ',,,,,,,,', ',,,,') --Repalce 8 ',' with 4 ','

PHP Array to string conversion, mysql_fetch_assoc() expects parameter [duplicate]

This question already has answers here:
mysql_fetch_array()/mysql_fetch_assoc()/mysql_fetch_row()/mysql_num_rows etc... expects parameter 1 to be resource
(31 answers)
Closed 8 years ago.
Can someone please help me with my code, I can't get it to work.
I have an html input form where I type for example "This is a sample".
(data is saved in $_POST['Begriff'])
I want to achive a simple translation, so that the table "drinks" in column "English" is checked for existence of every single word from my input sample sentence and output if found every entry from the corresponding row in one line.
Right now I have two problems:
As soon as I add " where English in $wert" to the select statement I get:
Notice: Array to string conversion in nachlesen.php on line 34
Warning: mysql_fetch_assoc() expects parameter 1 to be resource, boolean given
Second Problem: How to I put the sentence together again from the returned results?
(Right now I get the output for every found word below each other, instead of one line)
Here is my code:
if ( $_POST['Begriff'] <> "")
{
$wert = explode(' ',$_POST['Begriff']);
$select = mysql_query ("SELECT * FROM drinks where English in $wert");
while ( $row = mysql_fetch_assoc($select))
{
echo ("$row[German] <br>");
echo ("$row[English]<br>");
}
}
Thanks in Advance, Daniel
<?php
// premise: the user input in $_POST['Begriff'] is a string like 'This is a sample'
//first split it into single words
// preg_split: \s+ -> one or more whitespaces , PREG_SPLIT_NO_EMPTY -> no "empty" words
// e.g. " Mary had a little lamb" -> array('Mary','had','a','little','lamb')
$words = preg_split('!\s+!', $_POST['Begriff'], -1, PREG_SPLIT_NO_EMPTY);
// now encode each string so that it can be used
// safely as a string-literal within your sql query
// see: sql injection
// this should be:
// $words = array_map(function($e) use($mysql) { return mysql_real_escape_string($e, $mysql); }, $words);
// but apparently you're not storing the resource that is returned by mysql_connect
// mysql_real_escape_string() is applied to each single element in $words
// e.g. array("it's", "been") -> array("it\\'s", "been")
$words = array_map('mysql_real_escape_string', $words);
// now put the string literals into your query
// format: ... IN ('x','y','z')
// join(",", $words) gives you x,y,z
// join("','", $words) gives you x','y','z
// i.e. the first and the last ' has to be added "manually"
// keep in mind that for an empty array $words this will produce WHERE ... IN ('')
// better test that before even trying to build the query
$query = sprintf("
SELECT
German,English
FROM
drinks
WHERE
English IN ('%s')
", join("','", $words));
// send the query to the MySQL server
// should be: $result = mysql_query($query, $mysql);
$result = mysql_query($query);
// database query -> failure is always an option
if ( !$result ) {
// add error handling here
}
else {
// in case there is not a single match in the database
// your script would print ...nothing
// I don't like that - but that debatable
// anway: wrapped in a fieldset
echo '<fieldset><legend>results:</legends>';
while( false!==($row=mysql_fetch_array($result, MYSQL_FETCH_ASSOC)) ) {
printf('%s<br />%s<br />',
// just like on the input-side you had to worry about
// sql injections
// on the output side you want to avoid
// that characters from the database can break your html structure
htmlentities($row['German']),
htmlentities($row['English'])
);
}
echo '</fieldset>';
}
(script is untested)
why don't you try implode() and convert your array to string??
if ( $_POST['Begriff'] <> "")
{
//you'l have to replace all "spaces with ',' "
$pattern = '/\s*,\s*/';
$replace = "','";
$wert = preg_replace($pattern, $replace, $_POST['Begriff']);
$select = mysql_query ("SELECT * FROM drinks where English in ('$wert')");
while ( $row = mysql_fetch_assoc($select))
{
echo ("$row[German] <br>");
echo ("$row[English]<br>");
}
}
ANOTHER SOLUTION (TO PREVENT SQL INJECTION)
if ( $_POST['Begriff'] <> "")
{
//replace multiple spaces
$str1 = preg_replace( "/\s+/", " ", $_POST['Begriff'] );
//convert to array, separated by space
$arr=explode(" ",$str1);
$safe_params=array();
foreach($arr as $param){
$safe_params[]=mysql_real_escape_string($param);
}
$wert=implode("','",$safe_params);
$select = mysql_query ("SELECT * FROM drinks where English in ('$wert')");
while ( $row = mysql_fetch_assoc($select))
{
echo ("$row[German] <br>");
echo ("$row[English]<br>");
}
}
EDIT
Processing query output according to language
$german_words=array();
while ( $row = mysql_fetch_assoc($select))
{
$german_words[$row['English']]=$row['Gernam'];
}
//$str1 is having english string
echo "English: ".$str1."<br/>";
echo "German : ";
//$arr is having array of words of $str1
foreach($arr as $eng_word){
echo $german_words[$eng_word]." ";
}
"SELECT * FROM drinks where English in ('". implode("','", $wert) . "')"
EDIT: SQL Injection safe query:
$dsn = 'mysql:dbname=' . $settings['dbname'] . ';host=' . $settings['dbhost'];
$pdo = new PDO($dsn, $settings['dbuser'], $settings['dbpass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
if ( $_POST['Begriff'] <> "")
{
$wert = explode(' ',$_POST['Begriff']);
$placeholders = implode(',', array_fill(0, count($wert), '?'));
$sth = $pdo->prepare("SELECT * FROM drinks WHERE English in ({$placeholders})");
$sth->execute($wert);
$rows = $sth->fetchAll();
foreach($rows as $row) {
print_r( $row );
}
}

Escaping ' in a query-string - is it even possible?

I have a large php application (purely php, no frameworks, etc.) which uses an oracle-db.
All queries are executed like this:
oci_parse($conn_id,"insert into table (bla) values ('bla')");
oci_execute($stmt)
I know this is bad! No need pointing out stuff like "use bind" or something similar. I know that, but I can't change this.
What we all also know is that you have to escape characters.
This question is especially about the ' charcter.
I have many queries like this:
$query = "INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub', 'mimi'm', 'mu's'c'hle')";
$query2 = "UPDATE table SET field1 = 'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'"
Sure, normally they do not have so many ' in it - but thats just for demonstration.
Now to the question:
Is there any way to validate/escape the whole query-string in php? I can't think/find of a way to accomplish this, no matter how I think of it.
It's obvious that it's easy to escape all values before building the query-strings, by just replacing ' with '' - but is it possible when you only have the whole query as a string (like the examples above)? I personally can't think of an "universal solution"...
I believe this is insoluble with traditional means, at the time when the query is already built:
Trying to simply add a slash to every apostrophe, of course will not work, because you are escaping the delimiter apostrophes as well as the "in-value" apostrophes.
There is no function or regular expression to determine which are the in-value apostrophes and which are the value-delimiting apostrophes.
Even a parser won't help you because part of a parser's job is to tell you when the query has invalid syntax, but not to fix that syntax; as soon as it hits an apostrophe out of place and the following character is not a comma, it will baulk.
Let's take part of your second example:
field3 = 'mimi'm', field4 = 'mu's'c'hle'
A normal query parser would see the field3 value as 'mini' followed by an erroneous m, where it expects a comma. This is not something a parser is designed to handle.
So suppose we write something custom to handle this. Let's say we decide that the apostrophe, given that it isn't followed by a comma, must be part of the value. That's fine, but what about the next apostrophe, which is intended to be a delimiter?
How does our code know whether the apostrophe is a delimiter, as opposed to the value actually containing an apostrophe followed by a comma? In fact, the value could contain something that looks exactly like the rest of the query! (Furthermore, how would we detect queries that actually are invalid, once we start to question the structure of the query itself in this way).
tl;dr
GIGO = garbage in, garbage out
You can't write (traditional) software to sort out an arbitrary mess!
Okay, this is DEFINETELY not failproof, or even elegant, but it does work on the given querys, as a "proof of concept" so to speak...
do not use the function in a production server.. it WILL break sooner (not later ;))
<?php
$query = "INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi'm','mu's'c'hle')";
$query2 = "UPDATE table SET field1 = 'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'";
function clean_given_query($qry)
{
if(strpos($qry , " VALUES "))
{
//the easy way, since we know exactly how many fields we have here
$qra = explode('VALUES', $qry);
if(count($qra) == 2)
{
// qra[0] = "INSERT INTO table (field1, field2,field3,field4)"
// qra[1] = "('bla,bla','blub', 'mimi'm', 'mu's'c'hle')";
$qtemp = explode('(', $qra[0]);
$qtemp = $qtemp[1]; // we can loose the insert -part for now
$fieldcount = count(explode(',',$qtemp)); // now we know how many fields we want to populate
$qra[1] = explode("','", $qra[1]); // dirty values....
if(count($qra[1]) === $fieldcount) //make sure we have the correkt value count
{
$values = array();
foreach($qra[1] as $i => $val)
{
if($i==0)
$val = substr($val, 3); // we know $val is a string and index 0 starts with (' which we need to remove!
if($i == count($qra[1])-1) // last item needs to be cropped at the end
$val = substr($val, 0, count($val)-3); //also a string as we know.
$val = addslashes($val); //escape the string according to your needs
$values[] = $val;
}
return $qra[0]." VALUES ('".implode("','", $values)."')";
}
}
}
else if (strpos($qry, "SET"))
{
$qra = explode('=', $qry);
// $qra[0] = "UPDATE table SET field1";
// $qra[1] = "'bla,bla', field2";
$save = $qra[0]."='";
foreach($qra as $i => $mixed)
{
if($i == 0) // qra[0] holds nothing to edit!
continue;
$parts = explode(',', $mixed); // [0] 'bla [1] bla' [2] field2
$nextfield = array_pop($parts);
$val = implode(',', $parts); // $val = 'bla,bla'
if(strpos($nextfield , "WHERE"))
{
list($val, $nextfield) = explode("WHERE",$nextfield);
$nextfield = " WHERE ".$nextfield;
}
$val = trim($val);
$val = substr($val, 1, count($val)-2); //$val bla,bla
$val = addslashes($val); // escape according to your needs
if($val!=="" and strpos($nextfield , "WHERE") === false)
$save .= $val."', ".$nextfield."='";
elseif($val!=="" and strpos($nextfield , "WHERE"))
$save .= $val."' ".$nextfield."='";
else
{
$val = trim($nextfield);
$val = substr($val, 1, count($val)-2); //$val bla,bla
$val = addslashes($val); // escape according to your needs
$save .= $val."'";
}
}
return $save;
}
}
echo $query.PHP_EOL;
echo clean_given_query($query).PHP_EOL;
echo $query2.PHP_EOL;
echo clean_given_query($query2).PHP_EOL;
?>
Output:
INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi'm','mu's'c'hle')
INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi\'m','mu\'s\'c\'hle')
UPDATE table SET field1 = 'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'
UPDATE table SET field1 ='bla,bla', field2 ='blub', field3 ='mimi\'m', field4 ='mu\'s\'c\'hle' WHERE field5 ='lol\'zj\'d'
With a little bit of effort, and correct reg_exp instead of simple explode/implodes and the proper escape function for your needs you can build a function that is capable of cleaning given querys
You can use just do a simple str_replace(). I.E. str_replace("'", "\'", $string); .
EDIT:
You can also do
$str = "INSERT INTO table(field1, field2)
VALUES (
replace(" . $value . ", Chr(39), Chr(39) & Chr(39)),
replace(" . $value . ", Chr(39), Chr(39) & Chr(39))
);";
As Chr(39) refers to '.
If I understood your problem it should work
$name = addslashes("mu's'c'hle");
$query = "INSERT INTO teste (teste) VALUES ('$name')";
Unless you want to write something that can interpret the query and determine where the error is at and then somehow determine what the proper fix is, there is no way.
Further, if you do this you still haven't fixed your bigger issue, which is sql injection.
$query = "INSERT INTO table(field) Values('".addslashes("'")."')";
I think that's failsave or, even better
$query = sprintf("INSERT INTO table(field) Values('%s')", addslashes("'"));
because that's most liekely easier to read in case you want to extend the insert someday.
[edit]
as far as I know it doesn't matter which flavor of sql you use if you only want to have the strings escaped, but just in case addslashes works just as well here.
And yes... there are some specialised sql-escape functions in php,
And.. rereading the question.. just having the query-string, not having the initial values it's rather hard to properly escape everything.

Regex for number comparison?

I would like to perform regex to return true/false if the input 5 digit from input matching data in database, no need to cater of the sequence, but need the exact numbers.
Eg: In database I have 12345
When I key in a 5 digit value into search, I want to find out whether it is matching the each number inside the 12345.
If I key in 34152- it should return true
If I key in 14325- it should return true
If I key in 65432- it should return false
If I key in 11234- it should return false
Eg: In database I have 44512
If I key in 21454- it should return true
If I key in 21455- it should return false
How to do this using php with regex
This is a way avoiding regex
<?php
function cmpkey($a,$b){
$aa = str_split($a); sort($aa);
$bb = str_split($b); sort($bb);
return ( implode("",$aa) == implode("",$bb));
}
?>
Well, it's not going to be a trivial regex, I can tell you that. You could do something like this:
$chars = count_chars($input, 1);
$numbers = array();
foreach ($chars as $char => $frequency) {
if (is_numeric(chr($char))) {
$numbers[chr($char)] = $frequency;
}
}
// that converts "11234" into array(1 => 2, 2 => 1, 3 => 1, 4 => 1)
Now, since MySQL doesn't support assertions in regex, you'll need to do this in multiple regexes:
$where = array();
foreach ($numbers AS $num => $count) {
$not = "[^$num]";
$regex = "^";
for ($i = 0; $i < $count; $i++) {
$regex .= "$not*$num";
}
$regex .= "$not*";
$where[] = "numberField REGEXP '$regex'";
}
$where = '((' . implode(') AND (', $where).'))';
That'll produce:
(
(numberField REGEXP '^[^1]*1[^1]*1[^1]*$')
AND
(numberField REGEXP '^[^2]*2[^2]*$')
AND
(numberField REGEXP '^[^3]*3[^3]*$')
AND
(numberField REGEXP '^[^4]*4[^4]*$')
)
That should do it for you.
It's not pretty, but it should take care of all of the possible permutations for you, assuming that your stored data format is consistent...
But, depending on your needs, you should try to pull it out and process it in PHP. In which case the regex would be far simpler:
^(?=.*1.*1})(?=.*2)(?=.*3)(?=.*4)\d{5}$
Or, you could also pre-sort the number before you insert it. So instead of inserting 14231, you'd insert 11234. That way, you always know the sequence is ordered properly, so you just need to do numberField = '11234' instead of that gigantic beast above...
Try using
^(?=.*1)(?=.*2)(?=.*3)(?=.*4)(?=.*5).{5}$
This will get much more complicated, when you have duplicate numbers.
You really should not do this with regex. =)

Categories