Helpful Information
 
 
Category: Post a PHP snippet
Neat MySQL query function.

This is a little function I use to build INSERT and UPDATE queries. It makes it a lot simpler to do these queries and it escapes non numerical data too.


<?php
function build_query($type, $table, $array, $where = false, $value = false)
{
$type = strtoupper($type);
switch($type)
{
case 'UPDATE':
$ret = array();
foreach($array as $k => $v)
{
if(is_array($v))
{
$ret[] = '`' . $k . '` = `' . $k . '`' . $v[0];
}
else
{
$ret[] = '`' . $k . '` = ' . ((is_numeric($v)) ? $v : '\'' . mysql_real_escape_string($v) . '\'');
}
}
$ret = 'SET ' . implode(', ', $ret);
if($where && $value)
{
$ret .= ' WHERE `' . $where . '` = ' . ((is_numeric($value)) ? $value : '`' . $value . '`');
}
break;
case 'INSERT':
$type = 'INSERT INTO';
foreach($array as $k => $v)
{
$array[$k] = ((is_numeric($v)) ? $v : '\'' . mysql_real_escape_string($v) . '\'');
}
$ret = '(`' . implode('`, `', array_keys($array)) . '`) VALUES (' . implode(', ', $array) . ')';
break;
}
return $type . ' `' . $table . '` ' . $ret;
}
?>

It accepts 3 arguments
- The query type (INSERT or UPDATE).
- The tabel name.
- An array contining the data.
Heres an example on how to use this function.


<?php
define('TABLE_USERS', 'users');
$sql_data = array(
'user_name' => 'Marek',
'user_id' => 0,
'user_level' => 5,
'comment' => 'It really works!',
'counter' => array('+1')
);
$sql = build_query('UPDATE', TABLE_USERS, $sql_data, 'user_id', 4);
mysql_query($sql) or die($sql . "<br />\n" . mysql_error());?>

The array can not contian values of the following types: array, object, resource.

Why not have the name(s) of any id's as another argument to the function, so you wouldn't have to worry about appendingthe 'WHERE...' to the update?
So in your example you'd have


<?php
define('TABLE_USERS', 'users');
$sql_data = array(
'user_name' => 'Marek',
'user_id' => 0,
'user_level' => 5,
'comment' => 'It really works!'
);
$sql = build_query('UPDATE', TABLE_USERS, $sql_data,'user_id');
mysql_query($sql) or die($sql . "<br />\n" . mysql_error());
?>

From what I've seen in your code, the function doesn't support queries like "UPDATE `table` SET `column`= `column` + 1", does it?

dumpfi

Why not have the name(s) of any id's as another argument to the function, so you wouldn't have to worry about appendingthe 'WHERE...' to the update?

the WHERE part can be pretty complicated (WHERE `field` <= $number AND `otherfield` LIKE 'whatever'). It was just an example. It's would be easier to write that part yourself than tell a function to do it.... unless the whole WHERE statement would be the fourth argument.


From what I've seen in your code, the function doesn't support queries like "UPDATE `table` SET `column`= `column` + 1", does it?

Apart from adding that manually I don't think it would be that simple to identify if it's coded to increment or if it's user input. That's why I went with changing the type to array which has only one element.


<?php
function build_query($type, $table, $array)
{
$type = strtoupper($type);
switch($type)
{
case 'UPDATE':
$ret = array();
foreach($array as $k => $v)
{
if(is_array($v))
{
$ret[] = '`' . $k . '` = `' . $k . '`' . $v[0];
}
else
{
$ret[] = '`' . $k . '` = ' . ((is_numeric($v)) ? $v : '\'' . mysql_real_escape_string($v) . '\'');
}
}
$ret = 'SET ' . implode(', ', $ret);
break;
case 'INSERT':
$type = 'INSERT INTO';
foreach($array as $k => $v)
{
$array[$k] = ((is_numeric($v)) ? $v : '\'' . mysql_real_escape_string($v) . '\'');
}
$ret = '(`' . implode('`, `', array_keys($array)) . '`) VALUES (' . implode(', ', $array) . ')';
break;
}
return $type . ' `' . $table . '` ' . $ret;
}

define('TABLE_USERS', 'users');
$sql_data = array(
'user_name' => 'Marek',
'user_id' => 0,
'user_level' => 5,
'comment' => 'It really works!',
'counter' => array('+1')
);
$sql = build_query('UPDATE', TABLE_USERS, $sql_data) . ' WHERE `user_id` = ' . $sql_data['user_id'];
mysql_query($sql) or die($sql . "<br />\n" . mysql_error());
?>

I was thinking only for instances where you'd be updating one record based on a unique ID, and it's how 'Replace' works in ADODB

This is not a DBAL. Ok I'll add it becouse it really is the most common thing.
I updated my first post.

That seems a bit to complicated, really. I mean, why do that when you can make a function to connect and disconnect within the function, submit a query and then return the result. Maybe something like:


define('TABLE_USERS');
$result = query(TABLE_USERS, "INSERT * INTO users VAUES('', '".$username."', '".$userid."', '".$userlevel."', '".$comment."', '".$counter."')");
if ($row = @mysql_fetch_rows($result)) {

Doesn't it just... make sense? Maybe I'm not just seeing the uniqueness of your function, if so, I'm sorry. Can you explain the bonuses?

Yes.
It works very well with my form building class. :D Kind of odd as that function is older then the class.
Ok jokes aside. The function makes it simpler to build those queries.
BTW I don't see why I would want to connect and diconnect, yet alone get the result from an INSERT or UPDATE query.

Yes.
It works very well with my form building class. :D Kind of odd as that function is older then the class.
Ok jokes aside. The function makes it simpler to build those queries.
BTW I don't see why I would want to connect and diconnect, yet alone get the result from an INSERT or UPDATE query.


Err the last part was just from my function, I just edited the query. And why wouldn't you? It is in the top list of MySQL security, to connect and disconnect only when you need it, which was one of the points of original custom MySQL functions, so you didn't need to connect, you simply ran the query function.

Its actually less secure to connect and disconnect...more round trips for the data to be taken during transit. Also it would increase the connection overhead astronomically by connecting/disconnecting for every query. Just think, if you had 30 queries, that would mean connecting and disconnecting 30 times. 30 times for someone to intercept the connection info, 30 times the connection overhead.

Ok I didn't really understand what you've written. What is the part with connecting about. I never mentioned connecting or disconnecting.

Its actually less secure to connect and disconnect...more round trips for the data to be taken during transit. Also it would increase the connection overhead astronomically by connecting/disconnecting for every query. Just think, if you had 30 queries, that would mean connecting and disconnecting 30 times. 30 times for someone to intercept the connection info, 30 times the connection overhead.

What script runs 30 queries in one page? Hell, thats more then any script needs to do.

How about a forum or CMS?
I've seen pages do more that 100 queries (and still load quite fast).

How about a forum or CMS?
I've seen pages do more that 100 queries (and still load quite fast).

Well... they must be horrible forums and CMS's because here on Invision (1.3) it has less then 20, and on Droopal, one of the best CMS it has less then 10. At leat on the pages I'm looking at, I'll keep going through them. Anyway, been talking to Velox and understanding some different differences.

different differences.
You sure they're different? :p

You sure they're different? :p

I think so... Maybe not... :p

To add to this, I hope you wont mind me posting my own personal database class that I use almost all the time.


<?php

/*

MySQL Database Class
--------------------
Author: Matthew Wilson
Site: http://www.icdsoftware.com
Contact: admin at icdsoftware.com
License: Free for non-commercial use.

About
-----
Contains MySQL query operations within an object
as well as simplifying some query types.

*/

define('SQL_EXPRESSION', "--{0009def7886864195af0955f4b92bbb4cc1aaf099b3515e6ff0}--");

define('SQL_ROW', 'mysql_fetch_row');
define('SQL_ASSOC', 'mysql_fetch_assoc');


function expr($val = ''){
return array(
SQL_EXPRESSION,
$val
);
}


class mysql {

var $dbc;
var $cache;
var $querynum;
var $exec;
var $pconnect;
var $backquote;
var $serialize;

function __construct($settings = array()) {

list($user, $pass, $host, $db, $pconnect, $bq, $serialize) = $settings;
$this->pconnect = $pconnect;
$this->sqlconnect($user, $pass, $db, $host);

$this->exec = 0;
$this->cache = false;
$this->dbc = false;
$this->querynum = 0;
$this->backquote = $bq;
$this->serialize = $serialize;

}


function mysql( $settings = array() ){
if( $this->dbc == NULL ){
$this->__construct($settings);
}
}


function sqlconnect($user, $pass, $db, $host = 'localhost'){

$connection_function = 'mysql_connect';
if($this->pconnect == 1) {
$connection_function = 'mysql_pconnect';
}

if($this->dbc = @$connection_function($host, $user, $pass)){
if(@mysql_select_db($db, $this->dbc)){
return true;
} else {
return false;
}
} else {
return false;
}

}



function query($sql = ''){

$timer = explode(' ', microtime());
if($this->cache = @mysql_query($sql)){

$end_timer = explode(' ', microtime());
$difference = ($end_timer[0]-$timer[0])+($end_timer[1]-$timer[1]);
$this->exec += $difference;

++$this->querynum;
return $this->cache;

} else {

return false;

}

}



function fetch($result = NULL, $method = 'mysql_fetch_assoc'){

if($result === NULL){
$result = $this->cache;
}

if($result !== false){
if($result = $method($result)){
return $result;
} else {
return false;
}
} else {
return false;
}

}



function numrows($result = NULL){

if($result == NULL){
$result = $this->cache;
}

if($rows = @mysql_num_rows($result)){
return $rows;
} else {
return false;
}

}


function insertid(){
return @mysql_insert_id();
}


function affected(){
return @mysql_affected_rows();
}


function escape($str = ''){
return @mysql_escape_string($str);
}


function free($result = NULL){

if($result === NULL){
$result = $this->result;
}

return @mysql_free_result($result);

}


function close(){
return @mysql_close($this->dbc);
}


function getExec($round = 5){
return array(
'query_count' => $this->querynum,
'execution_time' => $this->exec
);
}


function insert($table, $key_value_array){
return $this->makeQuery($key_value_array, $table, 'insert');
}


function update($table, $key_value_array, $clause = ''){
return $this->makeQuery($key_value_array, $table, 'update', $clause);
}


function makeQuery($key_to_value_data = array(), $table = '', $type = 'insert', $clause = ''){

$query = '';
$bq = ($this->backquote == 1) ? '`' : '';
$table = "$bq$table$bq";

$_keys = array();
$_values = array();

foreach($key_to_value_data as $key => $value){

switch(gettype($value)){

case 'integer': case 'double': case 'boolean':
$_values[] = $value;
break;

case 'string': case 'resource': default:
$_values[] = "'".$this->escape($value)."'";
break;

case 'NULL':
$_values[] = 'NULL';
break;

case 'array':
if(isset($value[0]) && $value[0] == SQL_EXPRESSION){
$_values[] = $value[1];
break;
}

case 'object':
if($this->serialize == 1){
$_values[] = serialize($value);
} else {
settype($value, 'string');
$_values[] = $value;
}
break;

}

$_keys[] = $key;

}


if($type == 'insert'){

// Yes, this is the coolest variable name ever
$implosion = "$bq,$bq";
$fields = implode($implosion, $_keys);
$fields = "($bq$fields$bq)";

$values = implode(',', $_values);

if($values != ''){

$query = "INSERT INTO $table $fields VALUES ( $values )";

} else {

return false;

}

} else {

$update = '';
$count_keys = count($_keys);

for($i=0;$i<$count_keys;$i++){
$update .= "$bq{$_keys[$i]}$bq = {$_values[$i]}, ";
}

$update = substr_replace($update, "", -2);

if($update != ''){

$query = "UPDATE $table SET $update";
if($clause != ''){
$query .= " WHERE $clause";
}

} else {

return false;

}

}

if($result = $this->query($query)){
return $result;
} else {
return false;
}


}


}

?>


Some Examples:



<?php

$settings = array(
'username', // Database Username
'password', // Database Password
'host', // Database Host
'database', // Database Name
'pconnect', // Use a permanent connection ? (1 or 0)
'backquotes', // Whether or not to use backquotes in generated queries ( 1 or 0 )
'serialiaze' // When building queries using the easy methods (insert() & update()), should arrays/objects be automatically serialized?
);

// My Usual settings:
$mysql = array( 'root', 'rootpass', 'localhost', 'database', 0, 1, 1 );

$db = new mysql( $settings );

// You can then call all of the MySQL methods, such as:

$insert = array( 'field' => 'value' );
$db->insert( 'table_name', $insert );

// It will automatically escape values passed, so you dont have to run an escape on every value in the insert/update array.
// You might want to update:

$db->update( 'table_name', $insert, 'id=5' );

// If you need to use something like "fieldname = fieldname+x", use the expr() function:

$update = array( 'field', expr( 'field+7' ) );
$db->update( 'table_name', $update );

// Example query and result set:

$result = $db->query( "SELECT * FROM table" );
while( $row = $db->fetch( $result ) ){
// Code
}

Also, you can specify a function to use when fetching like so:

$db->fetch( $result, SQL_ROW ); // As set at the top of the page, or:
$db->fetch( $result, 'mysql_fetch_object' ); // Passing a string

?>

To add to this, I hope you wont mind me posting my own personal database class that I use almost all the time.

I don't even dare mind it. :D
I used adoDB but it seemed a bit too much for me. Since now we have the "ultimate" PHP5.1(.1) with PDO I think I'll check that out and if it's good I'll use it instead of anything I use now (with the exception of some neat functions ;) ).

Since now we have the "ultimate" PHP5.1(.1) with PDO I think I'll check that out and if it's good I'll use it instead of anything I use now (with the exception of some neat functions ;) ).

yeah definatley, I cant wait till 5.1.1 is mainstream, but at the moment with so many servers running 4.3.0 - 4.4.1 (I think i got the version numbers right) its no good using PDO.

[ Edited by missing-score: I just removed the very long quote of the earlier post ]

Thanks, thats what I'm doing in the edit page now. xD

Thats pretty sexy, missing-score. :) I like this, it almost feels like using MySQL with the same freedom.

Thanks Element :)

That is a nice db class. Mind if I use a few of the ideas (mainly the cool variable name, and the makeQuery())? Mine is internal...I doubt I'll ever post it in any way. Just curious (and probably missing something due to lack of sleep), but what purpose does the SQL_EXPRESSION serve?

Yeah of course you are free to use the ideas :)

The reason i have an SQL_EXPRESSION constant is to allow things like "var = var+1" as an update query. When you call the update() method, it takes an associative array. If you want to use an expression (eg: var + 1 ) you would do:



$update = array(
'var' => expr( 'var+1' )
);


The expr() function creates an array of the SQL_EXPRESSION constant, and the expression you entered. When it comes to building the query, datatypes are checked and escaped appropriately. 'var+1' would be treated as a string, and not give the desired effect.

If you look into the makeQuery function, you see when the switch loop gets to processing arrays, the first thing it does is checks fort the existance of the SQL_EXPRESSION constant as the first value. If it finds it, then it puts the value into the query as an expression rather than a string, and doesn't go on to potentially serialize the array (one of the options that you can set at the start -- automatically serialize arrays)

So I've invented it in almost the same way... that means that it was a good choice :)

missing-score, your class looks generally good.. one comment is to use mysql_real_escape_string. I was writing a similar abstraction for the Oracle/oci functions today although I was using objects and extending the base class then checking the class name instead of using constants like you did with expr() .. not sure if I'll convert over to your approach when I head in tomorrow but I have a feeling I will.
also, insert and update can have extremely similar syntax:

INSERT INTO table SET `col1`= 'blah';
UPDATE table SET `col1`= 'blah' WHERE `col2`='blah';

it would allow you to shed a couple lines (syntax reference (http://dev.mysql.com/doc/refman/5.0/en/insert.html))

ahh cool, I didnt realise that. If I ever get round to updating the class I will most likley change it.

one thing that could be done (for missing-score's):


class mysql_query_resource {
var $_query;
var $_rs;
var $_db;
function mysql_query_resource($query, $db) {
$this->_query = $query;
$this->_db = $db;
$this->_rs = @mysql_query($query, $db)
$this->is_error = !($this->_rs);
if (MYSQL_DEBUG && $this->isError()) { $this->getError(); }
}
function isError() {
return($this->is_error);
}
function getError() {
/* some error handling here */
}
function getResult($ field) {
return mysql_result($rs, 0, $field);
}
function getAssoc() {
return mysql_fetch_assoc($rs);
}
/* and so on ..*/
}
class mysql {
var $_db;
/* blah blah */
function query($query) {
return new mysql_query_resource($query, $this->_db);
}
/* blah blah */
}
// so..
$db = new mysql($connect);
$rs = $db->query("SELECT * From..");
while ($row=$rs->getAssoc()) {
print_r($row);
}
// and .. you get the idea.










privacy (GDPR)