Page 1 of 1

Skeleton Framework - initial thoughts

Posted: Mon Mar 17, 2008 11:19 am
by Mordred
I had a quick glance at the framework, and what I think it's major problem is, is an advanced form of OOP-ittis :)
Seriously, I don't think it's normal to have that amount of code split into that amount of files. Following a simple action requires opening of numerous files, where numerous objects delegate roles which noone would never want to change (so, there wasn't any need of that delegation in the first place). I don't have the code now so I can't give concrete examples at the moment, but the numbers kinda speak for themselves.

I went to take a look at the sql layer, and I'm unimpressed. The fluent interface is a nice OOP gimmick, but not very suitable for the task. While I'm all for using an SQL generator instead of writing SQL code, in the end the PHP becomes LONGER than the corresponding SQL code, with little to no added benefit. I would expect a generator to ease the majority of work related to writing SQL code. The only benefit I see from this is that a PHP interface is still better than string concatenation, and that you could still write an upper layer on top of this one and work with SQL from a higher level. The separation of SQL code and DB driver is also ok, but not really called for (IMO, could be wrong. Any of the authors care to justify it?)

There is a security vulnerability in the way SQL parameters are escaped, which would allow quoteless SQL injection to be used. I'll leave it as an exercise for the reader, at least until I go home and paste the code :)

Re: Skeleton Framework - initial thoughts

Posted: Mon Mar 17, 2008 12:40 pm
by John Cartwright
Mordred wrote:I had a quick glance at the framework, and what I think it's major problem is, is an advanced form of OOP-ittis :)
Seriously, I don't think it's normal to have that amount of code split into that amount of files. Following a simple action requires opening of numerous files, where numerous objects delegate roles which noone would never want to change (so, there wasn't any need of that delegation in the first place). I don't have the code now so I can't give concrete examples at the moment, but the numbers kinda speak for themselves.
We try to take loose-coupling as far as possible, and considering this framework focus is to not force convention on the user we want any components to be easily swappable and/or expendable. Our plan is to offer our implementation of the framework where all that is required is you run the default,

$bootstrap = new A_Bootstrap();

and all the components are defaulted to our implementation, however by creating your own bootstrap file the possibilities are endless.
I went to take a look at the sql layer, and I'm unimpressed. The fluent interface is a nice OOP gimmick, but not very suitable for the task. While I'm all for using an SQL generator instead of writing SQL code, in the end the PHP becomes LONGER than the corresponding SQL code, with little to no added benefit. I would expect a generator to ease the majority of work related to writing SQL code. The only benefit I see from this is that a PHP interface is still better than string concatenation, and that you could still write an upper layer on top of this one and work with SQL from a higher level. The separation of SQL code and DB driver is also ok, but not really called for (IMO, could be wrong. Any of the authors care to justify it?)

There is a security vulnerability in the way SQL parameters are escaped, which would allow quoteless SQL injection to be used. I'll leave it as an exercise for the reader, at least until I go home and paste the code :)
The SQL generation code, while is useful to be used as a standalone component, will also be used internally within other data access implementations, i.e. active records. By using the SQL generator, the underlying database no longer becomes important as it will generate valid SQL depending on which connection is passed (if none, defaults to mysql syntax/escaping). The point being, if you don't like the SQL generator, then you can simply pass your raw SQL directly as well and skip the SQL generator completely.

Mind you, the framework is still under development and very far from being bullet proof. I believe we are taking a step back from implementing the features and getting some test coverage on the components we have already done. Yes, shame on us for not unit testing first.

Please post any bug reports, and thanks for the comments! :)

Re: Skeleton Framework - initial thoughts

Posted: Mon Mar 17, 2008 2:32 pm
by Christopher
Great feedback ... really appreciated. The framework needs a lot of work and input like this is very helpful.
Mordred wrote:I had a quick glance at the framework, and what I think it's major problem is, is an advanced form of OOP-ittis :)
Seriously, I don't think it's normal to have that amount of code split into that amount of files. Following a simple action requires opening of numerous files, where numerous objects delegate roles which noone would never want to change (so, there wasn't any need of that delegation in the first place). I don't have the code now so I can't give concrete examples at the moment, but the numbers kinda speak for themselves.
You are right, the framework is split into a lot of files. I don't think that one class per file is that unusual. Maybe others can comment on that. But the main reason for splitting everything up has been to support implementation flexibility. The goal is that you don't have to include stuff you don't want. Perhaps that is a poor goal, or we have done a poor job achieving it.

I would be really interested to know what you think should be combined. It is quite possible that classes could be combined. The splits may be leftover from previous design ideas that are not longer needed.

I checked the number of files that need to be included in a bare bones system -- it is 5 classes. That included a Request, Registry, Front Controller and Mapper, plus a class to hold class/method names for the default and error actions. That could certainly be reduced. We could make it so you do not need a Registry. The FC and Mapper could be combined. And the class/name holder class could be turned into an array. There are reasons for those classes to be split, mainly to support alternate configurations, but perhaps they should still be combined. It is worth discussing.

Another solution might be a alternate combined class that supported a standard mix of features. There is currently also a simpler Front Controller that does not require any other classes if you want to use that (added to download at http://ap3.sourceforge.net/downloads/). Or you can just launch Actions as Page Controllers if you like.

I went back and checked a full featured bootstrap and it includes 15 files. That adds to the above list: View and Response classes, Router, Session, Config and Template classes. That sounds like a pretty standard mix. The reason for splitting things up is to allow programmers to use only the mix they want. Does that sound like too many files/classes to you? How many do you think is a good practice?

I am also interested to know if it is the number of classes or the number of files that is of concern. I think maybe it is the number of class because of your "OOP-ittis" remark. I would certainly like to eliminate any unnecessary delegation. I can provide some examples and the current rational if that would help you identify these problems.
Mordred wrote:I went to take a look at the sql layer, and I'm unimpressed. The fluent interface is a nice OOP gimmick, but not very suitable for the task. While I'm all for using an SQL generator instead of writing SQL code, in the end the PHP becomes LONGER than the corresponding SQL code, with little to no added benefit. I would expect a generator to ease the majority of work related to writing SQL code. The only benefit I see from this is that a PHP interface is still better than string concatenation, and that you could still write an upper layer on top of this one and work with SQL from a higher level. The separation of SQL code and DB driver is also ok, but not really called for (IMO, could be wrong. Any of the authors care to justify it?)
I generally agree with you that in most cases generator code is probably worse than plain SQL. The SQL classes you mention are completely optional however. There is also a Prepared Statement class available as another alternate way to generate SQL separate from the OO style classes you mention. None of these classes are required to make queries -- they just generate SQL strings that can be used with any database library. This is a good example of the loose coupling that we have tried to implement.

If you can think of improvement to the SQL generator's interface, please let us know. There is always room for improvement.
Mordred wrote:There is a security vulnerability in the way SQL parameters are escaped, which would allow quoteless SQL injection to be used. I'll leave it as an exercise for the reader, at least until I go home and paste the code :)
I would really like to know about this. The SQL classes are new and incomplete. We certainly want to fix this problem so if you can provide an example or patch to the code it would be greatly appreciated.

The framework is in an Alpha phase where the design is still fluid so all this input will have a real impact on the code. I hope you can become a little more familiar with the framework and give us deeper design input. Thanks ... and keep the criticisms coming! ;)

Re: Skeleton Framework - initial thoughts

Posted: Mon Mar 17, 2008 2:49 pm
by alex.barylski
I had a quick glance at the framework, and what I think it's major problem is, is an advanced form of OOP-ittis
Look whose part of the project (*cough* arborint *cough*). Did you really expect it not to utilize OOP almost exclusively 00 if not completely? :P

I'm an advocate for OOP so I don't think I agree with you on that one.
Seriously, I don't think it's normal to have that amount of code split into that amount of files.
Normal is all relative. While I agree they abstract the heck out of everything, that is intentional design choice I believe. Personally, I don't need or want that much flexibility, but in theory, it does lead to better design.
Following a simple action requires opening of numerous files, where numerous objects delegate roles which noone would never want to change (so, there wasn't any need of that delegation in the first place)
It's a trade off. On one hand, having multiple files, makes each file much more clear in it's purpose and easier to read -- my projects are even worse -- my files never have more than 100 lines of code. Personally, I see the bigger picture much easier than I do the implementation specifics. That is, the architectural diagram that I form in head of the whole system is much easier for me to process than starring at 500 lines of deeply nested, complex source code. I think this is strictly a personal choice. Obviously there are some people who can focus on a small part of a program and just "get it" -- I've worked with guys who had no problems sifting through 5000 lines of code in a single file. 8O
The separation of SQL code and DB driver is also ok, but not really called for (IMO, could be wrong. Any of the authors care to justify it?)
How do you support multiple RDBMS if you don't use drivers?
Yes, shame on us for not unit testing first.
Consdiering how much some of you bark about TDD as a best practice...yes shame on you. ;) :P

Jcart: Assuming you are part of the project. One thing I wanted to ask arborint while having this disscussion previously (just been damn busy). Fundementally, how does your framework differ from that of Zend?

While looking over it -- conceptually -- it seems to be similar to Zend in it's liberal use of abstraction and total flexibility. What road blocks did you encounter specifically with Zend to make you all consider developing yet another -- learning experience???

Cheers :)

Re: Skeleton Framework - initial thoughts

Posted: Mon Mar 17, 2008 4:26 pm
by Christopher
Hockey wrote:One thing I wanted to ask arborint while having this disscussion previously (just been damn busy). Fundementally, how does your framework differ from that of Zend?
It is similar to Zend in that it is not a tightly coupled full-stack framework. It is also patterns based and uses PEAR naming, so there are some superficial naming similarities. But I think it is generally lighter weight and more configurable.

Some of the design goals for the project have been:

- Be as loosely coupled as is reasonably possible
- Add features by combining objects or adding layers, not enlarging classes.
- Try to make the minimum requirements as minimal as possible (yet actually be a framework ;). See above for the 1 or 5 file bootstrap vs. a full featured 15 include version.
- Action Controller not required inherit a base class (but there are 4-5 options they can inherit)
- Programmer can choose between error handlers or exceptions
- Plan to provide support popular class libraries like Smarty/TemplateLite, ADOdb, etc.
- In general encourage choices. The example from above, there is support for plain SQL, prepared statements and OO SQL styles. For database it not just Model/ActiveRecord, but TableDataGateway or DataMapper too.
- Allow the use of components from other frameworks like Zend.
- Examples that just work

I am not saying that we have completely achieved all of that, but it should give you as sense of the differences.
Hockey wrote:While looking over it -- conceptually -- it seems to be similar to Zend in it's liberal use of abstraction and total flexibility. What road blocks did you encounter specifically with Zend to make you all consider developing yet another -- learning experience???
You can read about this in some of the threads in the forum. I think Ninja was the last to become annoyed with Zend.

Re: Skeleton Framework - initial thoughts

Posted: Mon Mar 17, 2008 4:47 pm
by alex.barylski
You can read about this in some of the threads in the forum. I think Ninja was the last to become annoyed with Zend.
Haha...yes I remember his rant. :P

Re: Skeleton Framework - initial thoughts

Posted: Tue Mar 18, 2008 5:10 pm
by Mordred
I couldn't find time to comment more on (or indeed read more of) the framework design, so for now I'll only post the vulnerable code. I think it can't be fixed and that it comes from the inherently wrongness of the system, but I don't have time to elaborate on that right now.

in A_Sql_Abstract:

Code: Select all

    public function quoteValue($value) {
        $value = trim($value, '\''); //incase the user already quoted the value
        if (preg_match('/^[a-z\_]*\(/i', $value) || ctype_digit($value)) { //detect if the value is a function or digits
            return $value;
        }       
        return '\''. $value .'\'';
    }
Any value that has a ( in it will be exempt from quoting, and moreover will have any existing quoting stripped. The attacker can then use quoteless SQL injection techniques even if the $value was properly escaped.

I now notice another, more interesting attack vector, although it is a bit harder to exploit, you need to be able to inject two strings in a query (it's not that uncommon at all, actually). The trim() will work incorrectly on a quoted escaped string:
'test' --escape--> \'test\' --trim--> \'test\ --return--> '\'test\' (a quote is missing in the end)

Anything after that will be eaten until the second one comes. The second string's starting quote will actually close this one's, and the entire second string will be interpreted as SQL code.

P.S. Hey, the code tag doesn't handle this correctly:
'\'' (quote slash quote quote)

Code: Select all

'\''
P.P.S. Smurf, look at the time! I'm offski

Re: Skeleton Framework - initial thoughts

Posted: Tue Mar 18, 2008 5:34 pm
by Christopher
Good find. I think Jcart and I had discussed this and decided not to quote functions. I recall that we ended up quoting where the programmer provides a value, otherwise assume that the quoting was done elsewhere. It is not practical to know all the parameters for all the functions. Perhaps we could explode the parameter list and re-assemble it quoting each value. But what if there are functions as parameters?

I think we need to provide a solution for this though. What do you recommend? Do we make the default to quote everything and you need to turn it off if you want functions ignored? Perhaps we need to rethink the whole idea of quoting and escaping?

I was actually hoping that you had some criticism of the core of the framework -- the Filters, Validators, MVC classes, etc. Those OO SQL classes and the prepared statement class (A_Sql_Prepared) are both options for people who like to use that style to solve certain problems. But they are very peripheral and we could just remove them or post a strong warning about them if we can't come up with a resolution.

Everyone else is invited to criticize as well. We will make changes to address criticisms and the framework will be better for it.

Re: Skeleton Framework - initial thoughts

Posted: Wed Mar 19, 2008 5:24 pm
by Christopher
Mordred wrote:I think it can't be fixed and that it comes from the inherently wrongness of the system, but I don't have time to elaborate on that right now.
I think you are right about this. I do not see good way to support mixing values and functions in any reasonable way. For those not familiar, the code in question is used to build expressions for WHERE statements and UPDATE SET assignments like this:

Code: Select all

 
$condiitions = array('foo'='Hello', 'bar'=1);
$sql = $select->table('example')->where($conditions)->render();
// output will be "SELECT * FROM example WHERE foo='Hello' AND bar=1"
 
$sql = $update->table('example')->set($conditions)->where('id', 42)->render();
// output will be "UPDATE example SET foo='Hello', bar=1 WHERE id=42"
 
The quoting support is optional, so we should either:

1. Quote everything and allow the programmer to turn it OFF to add functions on the right side of expressions.

2. Quote nothing and allow the programmer to turn it ON if they want to add quotes to values on the right side of expressions.

Morderd, Jcart, others? Which one is preferable?

You had an additional potential exploit, but I don't see how you could "inject two strings". But we should look into that.

Re: Skeleton Framework - initial thoughts

Posted: Thu Mar 20, 2008 2:04 am
by Mordred
arborint wrote:
Mordred wrote:I think it can't be fixed and that it comes from the inherently wrongness of the system, but I don't have time to elaborate on that right now.
I think you are right about this. I do not see good way to support mixing values and functions in any reasonable way.

The quoting support is optional, so we should either:

1. Quote everything and allow the programmer to turn it OFF to add functions on the right side of expressions.
2. Quote nothing and allow the programmer to turn it ON if they want to add quotes to values on the right side of expressions.
Morderd, Jcart, others? Which one is preferable?
Err, false dilemma, I think.
You should remove the code altogether. In the generated code everything coming from outside should be assumed to be value and unconditionally quoted. Implement SQL functions handling in another way. Here's a possible way, though I haven't given it much thought, so take with a pinch of salt.

Code: Select all

$functions = new A_Sql_Functions();
$select->columns('*')->from(array('foobar'))->where(Array("foo" => $functions->Rand(5)));
arborint wrote:You had an additional potential exploit, but I don't see how you could "inject two strings". But we should look into that.
Yep, I wrote some test code and it's working beautifully. Here's a modified example_select.php :

Code: Select all

<?php
 
include 'config.php';
include 'A/Sql/Select.php';
 
$select = new A_Sql_Select();
$select->columns('foo, baz')
         ->from(array('foobar'))
         ->where(Array("foo" => "bar"))
         ->where(Array("baz" => "qux"));
echo "<br>" . $select->render() . '<br/>';
 
$select = new A_Sql_Select();
$select->columns('foo, baz')
         ->from(array('foobar'))
         ->where(Array("foo" => "'bar'"))
         ->where(Array("baz" => "qux"));
echo "<br>" . $select->render() . '<br/>';
 
$select = new A_Sql_Select();
$select->columns('foo, baz')
         ->from(array('foobar'))
         ->where(Array("foo" => "'bar'"))
         ->where(Array("baz" => " AND 0) UNION SELECT ALL username, password FROM login /*"));
echo "<br>" . $select->render() . '<br/>';
?>

Output:

(normal query)

Code: Select all

SELECT foo, baz FROM foobar WHERE (foo = 'bar') AND (baz = 'qux') 
 
(just a broken query; added a quote to fix the highlighting)

Code: Select all

SELECT foo, baz FROM foobar WHERE (foo = '\'bar\') AND (baz = 'qux') -----(additional quote, not in actual output)----> ' 
 
(exploit)

Code: Select all

SELECT foo, baz FROM foobar WHERE (foo = '\'bar\') AND (baz = ' AND 0) UNION SELECT ALL username, password FROM login /*') 
 
 
 

P.S. I still haven't looked at the other code; the reason I chose the sql generator is that, first, it's related to security, which is a favourite topic of mine, and second, in my framework that's the part that took the most thought, choices, refactoring and lines of code.

Re: Skeleton Framework - initial thoughts

Posted: Thu Mar 20, 2008 3:22 am
by Christopher
First of all I want to thank you. I think you are brilliant. Your scorched earth attitude is exactly what is needed. I love being shown how bad my code is, because I get to learn plus get improved code.

You are right, trying to be smart about quoting functions needed to be removed -- and it has. I just committed changes to the A_Sql_Abstract, A_Sql_Equation and A_Sql_Expression to get rid of that code (you can get the code from the download page). Now every value is escaped and then quoted. There are probably further exploits, so I hope you will give it your worst! ;)

I also realized that there is already a way to add an expression with an equation, so that capability was not needed. There are four ways to pass expression data:
1) where("foo!=NOW()") generates foo!=NOW()
2) where("foo>", "bar") generates foo>'bar'
3) where("foo", "bar") generates foo='bar'
4) where(array("foo!=NOW()", "foo>"=>"bar", "foo"=>"bar")) generates foo!=NOW() AND foo>'bar' AND foo='bar'

Here is a slightly expanded version of your test code:

Code: Select all

include 'A/Sql/Select.php';
 
$select = new A_Sql_Select();
$select->columns('foo, baz')
         ->from(array('foobar'))
         ->where(Array("foo" => "bar"))
         ->where(Array("baz" => "qux"));
echo "<br>" . $select->render() . '<br/>';
 
$select = new A_Sql_Select();
$select->columns('foo, baz')
         ->from(array('foobar'))
         ->where(Array("foo" => "'bar'"))
         ->where(Array("baz" => "qux"));
echo "<br>" . $select->render() . '<br/>';
 
$select = new A_Sql_Select();
$select->columns('foo, baz')
         ->from(array('foobar'))
         ->where(Array("foo" => "'bar'", "time=NOW()", "foo>"=>42))
         ->where(Array("baz" => " AND 0) UNION SELECT ALL username, password FROM login /*"));
echo "<br>" . $select->render() . '<br/>';
The output now is:

SELECT foo, baz FROM foobar WHERE (foo='bar') AND (baz='qux')

SELECT foo, baz FROM foobar WHERE (foo='bar') AND (baz='qux')

SELECT foo, baz FROM foobar WHERE (foo='bar' AND time=NOW() AND foo>'42') AND (baz=' AND 0) UNION SELECT ALL username, password FROM login /*')

Re: Skeleton Framework - initial thoughts

Posted: Thu Mar 20, 2008 4:49 pm
by Mordred
arborint wrote:First of all I want to thank you. I think you are brilliant. Your scorched earth attitude is exactly what is needed. I love being shown how bad my code is, because I get to learn plus get improved code.
Yeah, it's reciprocal - I like the way you approach the coding of this thing ;) I mean - some people seem to confuse themselves with their code, and take critique on their code as personal insult... I often forget this, as in my work I get to criticise other people's code, and my code gets criticised, and the net result is - yep, you said it - better code.
arborint wrote:You are right, trying to be smart about quoting functions needed to be removed -- and it has. I just committed changes to the A_Sql_Abstract, A_Sql_Equation and A_Sql_Expression to get rid of that code (you can get the code from the download page). Now every value is escaped and then quoted. There are probably further exploits, so I hope you will give it your worst! ;)
No exploit there, as far as I can see now, but still a bit buggy:
1. Remove the trim. If the user has quoted the value, he wanted these quotes as part of the value, so you must keep them (escaping will take care of them). Also, since you trim before the escaping, you won't actually trim them anyway.
Unless, the user wanted to have a slash-quote - then it will just be gone.
2. What's the difference between Expression and Equation? (The latter should go, I think)
3. I don't see a purpose for A_Sql_Abstract at all. Note that while Expressions and Columns may need quoting, they may need *different* quoting (as is the case with MySQL). I believe Expression should have the quoting function, and since it has a new semantic, maybe rename it to something like quoteAfterEscape(), escapeAndQuote() or whatever.
4. Ah, it's called quoteEscape() in Prepare. That one needs fixing too.
arborint wrote: I also realized that there is already a way to add an expression with an equation, so that capability was not needed. There are four ways to pass expression data:
1) where("foo!=NOW()") generates foo!=NOW()
2) where("foo>", "bar") generates foo>'bar'
3) where("foo", "bar") generates foo='bar'
4) where(array("foo!=NOW()", "foo>"=>"bar", "foo"=>"bar")) generates foo!=NOW() AND foo>'bar' AND foo='bar'
You'll quickly find the problem in the moment you try it with - say - MD5() of a user-supplied password, instead of NOW().

$land = new Land('never-never')
$this->SetLocation($land);

Re: Skeleton Framework - initial thoughts

Posted: Thu Mar 20, 2008 9:06 pm
by Christopher
Mordred wrote:Yeah, it's reciprocal - I like the way you approach the coding of this thing ;) I mean - some people seem to confuse themselves with their code, and take critique on their code as personal insult... I often forget this, as in my work I get to criticise other people's code, and my code gets criticised, and the net result is - yep, you said it - better code.
Wholeheartedly agreed. I really just want better, more flexible code. I have found the experience of working with a group to be very rewarding. This framework is very open to suggestions, additions, improvements. My goal is to make it the framework that doesn't have something you hate about it. That is lets you code in your current style while gently encouraging best practices.
Mordred wrote:No exploit there, as far as I can see now, but still a bit buggy:
1. Remove the trim. If the user has quoted the value, he wanted these quotes as part of the value, so you must keep them (escaping will take care of them). Also, since you trim before the escaping, you won't actually trim them anyway.
Unless, the user wanted to have a slash-quote - then it will just be gone.
trim() removed.
Mordred wrote:2. What's the difference between Expression and Equation? (The latter should go, I think)
Equation deleted.
Mordred wrote:3. I don't see a purpose for A_Sql_Abstract at all. Note that while Expressions and Columns may need quoting, they may need *different* quoting (as is the case with MySQL). I believe Expression should have the quoting function, and since it has a new semantic, maybe rename it to something like quoteAfterEscape(), escapeAndQuote() or whatever.
Abstract deleted. I moved the methods into the classes where they were used. I should comment that Jcart wanted to do this too, but I wanted to keep it. Not waiting for three strikes. ;)
Mordred wrote:4. Ah, it's called quoteEscape() in Prepare. That one needs fixing too.
Changed to be the same as the one in Expression.
Mordred wrote:You'll quickly find the problem in the moment you try it with - say - MD5() of a user-supplied password, instead of NOW().
I think my point was that if someone does where("foo!=MD5('$username')") instead of where("foo!=MD5('" . $db->escape($username) . "')") it's their own damn fault. However, I did have the idea of maybe providing something like this (either checking for three or more parameters, or a new method):

where("foo!=", 'MD5', $username)
whereFunction("foo=", 'DATE_FORMAT', $date, '%d/%m/%Y')
Mordred wrote:$land = new Land('never-never')
$this->SetLocation($land);
:)

Really good changes. Please as you have time keep going. The code is improved and smaller. I uploaded the latest to the http://ap3.sourceforge.net/downloads/

Re: Skeleton Framework - initial thoughts

Posted: Fri Mar 21, 2008 2:19 am
by Chris Corbyn
Doesn't parameter binding solve a lot of these issues? I know you'd have to lose support for the standard MySQL extension unless you emulated binding in this case though.

EDIT | Hmm, it'd be so confusing to combine SQL generation with binding though since you'd have to generate SQL with the placeholders in then bind parameters at execution time.

Re: Skeleton Framework - initial thoughts

Posted: Fri Mar 21, 2008 5:43 am
by Christopher
Chris Corbyn wrote:Doesn't parameter binding solve a lot of these issues? I know you'd have to lose support for the standard MySQL extension unless you emulated binding in this case though.
Yes is does. So you could use the MySQLi or PDO parameter binding to do the same thing. There are classes here to do OO style SQL generating like shown above. Plus there is also a prepared statement class that supports that the parameter binding style of SQL generation. One goal is simply to provide options to support different styles.

This code is actually a bunch of little classes that you can use to generate whole SQL statements or parts of them. So while there are classes for SELECT, INSERT, UPDATE, DELETE, there are also classes for JOINs, expressions, expression lists, etc. The classes use the driver's escaping function if provided. Since they only output a SQL sting and don't do queries there is very low coupling.

The classes provide a nice interface if programmers what to use them, but the real reason for them was to provide internal support for some of the higher level classes like ActiveRecord and DataMapper that need SQL building internally (and can't depend on a specific driver).
Chris Corbyn wrote:EDIT | Hmm, it'd be so confusing to combine SQL generation with binding though since you'd have to generate SQL with the placeholders in then bind parameters at execution time.
Not really. You could use these functions to generate SQL statements with ?'s for placeholders and then give it a DB library. This code is to help when, for example, you have arrays of column data and want to generate SQL from the data rather than hard code it.