|
View:
New views
16 Messages
—
Rating Filter:
Alert me
|
|
|
find() method shouldn't use intval() when primary key is int
I posted this on the issue tracker to verify that it's not a bug, so
hereby I want to make my statement that I don't agree with the find()
method using intval (or something like that) when my primary key is an
integer. Let's say I have the following record in my database:
id (PK) = 2 title = Lorem text = Lorem ipsum In my code, I use $this->find(2) to retrieve this record. This works great, however $this->find('2abc') also retrieves this record. In my opinion, this doesn't make any sense as "SELECT * FROM myTable WHERE id = '2abc'" wouldn't return it either. Instead, the fact that ZF knows whether my primary key is an integer, perhaps in this case $this->find('2abc') should return an error saying that the provided key doesn't match the data type of my primary key. I am looking forward to hearing your opinions about this. Dimitri --
Met vriendelijke groet, Dimitri van Hees - - Dimitri van Hees dimitri@... freshheads grafisch ontwerp en internet applicaties Dunantstraat 1c | 5017 KC Tilburg | Nederland tel. +31 (0)13 5448761 | fax. +31 (0)13 5448762 info@... | www.freshheads.com |
|
|
Re: find() method shouldn't use intval() when primary key is intI think to some extent it comes down to data validation before you use the find() method. So if your working with user input data and expect an ID you should be validating that the data is an int.
/James Dempster On Fri, Jun 13, 2008 at 9:13 AM, Dimitri van Hees <dimitri@...> wrote:
|
|
|
|
|
|
Re: find() method shouldn't use intval() when primary key is intZend_Db is not doing this mapping. The intval() function does not appear anywhere in Zend_Db_Table or related classes. Furthermore, it's not even PHP or the database extension doing this mapping. What you're seeing is standard behavior of MySQL (and perhaps other databases). You can reproduce this behavior without using PHP at all, just use the MySQL command-line tool: mysql> CREATE TABLE test.foo (i INTEGER); mysql> INSERT INTO test.foo VALUES (1), (2), (3); mysql> SELECT * FROM test.foo WHERE i = '2abc'; +------+ | i | +------+ | 2 | +------+ 1 row in set, 3 warnings (0.02 sec) I don't know any way of changing this behavior of MySQL. Regards, Bill Karwin |
|
|
Re: find() method shouldn't use intval() when primary key is intNot so sure about that Bill,
In trunk line 997 of Zend/Db/Table/Abstract.php $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE']; $whereAndTerms[] = $this->_db->quoteInto( $this->_db->quoteIdentifier($keyNames[$keyPosition], true) . ' = ?', $keyValue, $type); It's reading in the type and passing that type on to quoteInto of the db adapter which then passes it onto quote of the db adapter line 770 of Zend/Db/Adapter/Abstract.php line 792 case Zend_Db::INT_TYPE: // 32-bit integer $quotedValue = (string) intval($value); break; It also covers many other types. I personally am much happier with it doing it this way. It allows for much cleaner sql queries with values that match the actual db types. Some dbs have problems with casting differencing values for columns types etc. The real answer to this problem is validate, it's obviously impossible for a int column primary key to contain the required value. As another solution you could always extend the class and overload the query method and deal with it differently. /James Dempster On Fri, Jun 13, 2008 at 4:00 PM, Bill Karwin <bill@...> wrote:
|
|
|
Re: find() method shouldn't use intval() when primary key is intP.S.
Postgres will report an error with that SQL. ERROR: invalid input syntax for integer: "2abc" where as MySQL does exactly as you said. On Fri, Jun 13, 2008 at 4:00 PM, Bill Karwin <bill@...> wrote:
|
|
|
Re: find() method shouldn't use intval() when primary key is intThanks for your opinions, however I still don't agree, whether it's MySQL or Zend Framework itself ;-) I guess I'll just have to extend the class to my appearantly strange opinion about this, but to me it's a pity that the following code doesn't work right now: if($record = $db->find($this->id)) { var_dump($record); } else { //404 } In our case $this->id comes from the url, knowing that any security issues are already handled by the framework/find function itself, so SQL injections won't be possible (right?). As there is no record with PK = 5, there also isn't a record with PK = '2abc'. The only record I have should be PK = 2. I don't see why the find() method handles find(5) different than find('2abc') when both primary keys don't exist. Thanks again, Dimitri James Dempster wrote: Not so sure about that Bill, --
Met vriendelijke groet, Dimitri van Hees - - Dimitri van Hees dimitri@... freshheads grafisch ontwerp en internet applicaties Dunantstraat 1c | 5017 KC Tilburg | Nederland tel. +31 (0)13 5448761 | fax. +31 (0)13 5448762 info@... | www.freshheads.com |
|
|
Re: find() method shouldn't use intval() when primary key is intAha, good catch. I stand corrected. Nevertheless, MySQL does do automatic string-to-intval mapping in its flavor of SQL. Perhaps this isn't advisable, for the reasons Dimitri states, but the point is that even if Zend_Db weren't doing this, MySQL still would (if you use MySQL). Now I remember, I had to do the intval() based on the datatype in quoteInto() because Oracle complains if you pass a string value to be compared to an integer column. In other words, the following expression is a fatal error in Oracle: WHERE id = '2' Yet Oracle returns integer datatypes as strings (because 64-bit Oracle integers exceed the capacity of a 32-bit PHP integer). Zend_Db_Table_Row uses that string when forming SQL queries for save() or findDependentRowset() etc., so the value must not have quotes around it. In the quoteInto() method, one could simply take the argument verbatim, but not quote it if it's supposed to compare to an integer column. But that would create a bad security flaw in an unexpected place, so a call to find('3 OR 1=1') would be a vector for SQL injection. Therefore the best thing I could do is use intval() to ensure the argument of quoteInto() is safe, if it mustn't be quoted because $type says it's an integer. For BIGINT, a regular expression is used instead of intval(), so 64-bit integer values won't be truncated. Regards, Bill Karwin |
|
|
Re: find() method shouldn't use intval() when primary key is intThe reason is that 5 is a valid integer and is passed through to the SQL executed by the database server, which finds no row with that PK value. '2abc' is filtered to a valid integer, which is 2, and this PK value is found. If quoteInto() didn't do this filtering, it would be a SQL injection vulnerability, but if quoteInto() quoted the string to prevent SQL injection, this would be invalid SQL on database brands that require integer literals to be unquoted. Regards, Bill Karwin Regards, Bill Karwin |
|
|
RE: find() method shouldn't use intval() when primary key is intWith regard to Oracle, I think you must be mistaken. Using the Oci8
driver, the following queries return the same result: Query 1: select * from tst where id = '2' Result 1: array ( 0 => '2', 'ID' => '2', ) Query 2: select * from tst where id = 2 Result 2: array ( 0 => '2', 'ID' => '2', ) Craig Duncan -----Original Message----- From: Bill Karwin [mailto:bill@...] Sent: Friday, June 13, 2008 11:55 AM To: fw-db@... Subject: Re: [fw-db] find() method shouldn't use intval() when primary key is int JDempster wrote: > > Not so sure about that Bill, > > It's reading in the type and passing that type on to quoteInto of the db > adapter which then passes it onto quote of the db adapter line 770 of > Zend/Db/Adapter/Abstract.php > Aha, good catch. I stand corrected. Nevertheless, MySQL does do automatic string-to-intval mapping in its flavor of SQL. Perhaps this isn't advisable, for the reasons Dimitri states, but the point is that even if Zend_Db weren't doing this, MySQL still would (if you use MySQL). Now I remember, I had to do the intval() based on the datatype in quoteInto() because Oracle complains if you pass a string value to be compared to an integer column. In other words, the following expression is a fatal error in Oracle: WHERE id = '2' Yet Oracle returns integer datatypes as strings (because 64-bit Oracle integers exceed the capacity of a 32-bit PHP integer). Zend_Db_Table_Row uses that string when forming SQL queries for save() or findDependentRowset() etc., so the value must not have quotes around it. In the quoteInto() method, one could simply take the argument verbatim, but not quote it if it's supposed to compare to an integer column. But that would create a bad security flaw in an unexpected place, so a call to find('3 OR 1=1') would be a vector for SQL injection. Therefore the best thing I could do is use intval() to ensure the argument of quoteInto() is safe, if it mustn't be quoted because $type says it's an integer. For BIGINT, a regular expression is used instead of intval(), so 64-bit integer values won't be truncated. Regards, Bill Karwin -- View this message in context: http://www.nabble.com/find%28%29-method-shouldn%27t-use-intval%28%29-whe n-primary-key-is-int-tp17818272p17826612.html Sent from the Zend DB mailing list archive at Nabble.com. |
|
|
RE: find() method shouldn't use intval() when primary key is intWell I'm not an Oracle expert, and I don't have it installed right now so I can't test. The behavior might vary by version, by platform, or perhaps there's a config option with which one can change this behavior. I don't know. I tested with Oracle XE 10g on Windows XP. I wrote hundreds of unit tests for Zend_Db, running identical SQL queries against multiple brands of database. A query that compared a number column to a quoted integer literal worked on MySQL but threw an error on Oracle. Take that as you will. Regards, Bill Karwin |
|
|
Re: find() method shouldn't use intval() when primary key is intI didn't follow the whole conversation but here a suggestion. Would it help if we do something like this:
case Zend_Db::INT_TYPE: // 32-bit integer if($value != intval($value)){ //throw error that this is not an int } $quotedValue = (string) intval($value); break; Just a thought. Gunter On Fri, Jun 13, 2008 at 11:19 AM, Bill Karwin <bill@...> wrote:
|
|
|
Re: find() method shouldn't use intval() when primary key is intmight be best to do something like
if((string)intval($this->id)) == (string)$this->id && $record = $db->find($this->id)) { var_dump($record); } else { // 404 } If you're using MySQL as a db or even Oracle it sounds like you don't have a choice, because it looks like the db will cast it for you in much the same way that Zend_Db does. If you're using using Postgres (tested on 8.0) then it would have caused an Exception from an invalid SQL query. I much prefer the way ZF deals with it. It's constant across all db's. /James Dempster On Fri, Jun 13, 2008 at 4:29 PM, Dimitri van Hees <dimitri@...> wrote:
|
|
|
|
|
|
Re: find() method shouldn't use intval() when primary key is int |