how to use regular pdo in CI - php

i am used to writing regular pdo statements into php how can i continue doing that without having to learn active records or use whatever else method there is in CI
i did something like this
$sql = "select column1,column2 from table where column_id = :column_id and column_2 = :something"
$query = $db->query($sql);
$query->bindParam(":column_id", $_GET['value'], PDO::PARAM_INT);
$query->bindParam(":something", $_GET['something'], PDO::PARAM_STR);
$query->execute();
while($row = $query->fetch(PDO::FETCH_OBJ)
{
print $row->data;
}
rather than using $_GET i can probably use $this->uri->segment()
which hopefully works with this...
I looked at active record and that looks like a huge bad idea, i dont know what Ellislab was thinking. no clue how complex queries can go into them. I am a newb learning from nettuts i can be wrong and please show me if i am. just speaking from what i have learned so far.
writing query statments the otherway such as
$query = $this->db->query("my sql statement") i would have to escape each value i am querying with codeigniters escape methods or just use mysql_real_escape_string. which is something i could of done to begin with before diving into the mvc world but i chose pdo because its something that already works well.
how can i implement what i am already used to?? I dont mind modifying core files , ill hopefully end up learning all the classes to reverse engineer it but until that day comes i'll have hopefully written my own mvc.
thanks

Sorry, I fail to see how this:
$query = $this->db->select('column1,column2')
->from('table')
->where('column_id',$this->input->get('value'))
->where('column_2',$this->input->get('something'))
->get();
return $query->results();
"looks like alot of extra work" rather than this:
$sql = "select column1,column2 from table where column_id = :column_id and column_2 = :something"
$query = $db->query($sql);
$query->bindParam(":column_id", $_GET['value'], PDO::PARAM_INT);
$query->bindParam(":something", $_GET['something'], PDO::PARAM_STR);
$query->execute();
Keep in mind that AR automatically escapes, so you don't worry about SQL injections.
If you're more used to query bindings, you can also do
$sql = "select column1,column2 from table where column_id = ? and column_2 = ?";
$query = $this->db->query($sql, array($this->uri->segment(3), $something);
and take advantage of parametrization, without using Active Record class.
Nothing prevents you from using PDO, or even mysql_* for what that matters, instead of Active Record class. And your query has nothing that prevents CI from using it - apart from the $_GET array which you must enable, but can easily subsitute with $this->input->get() or fetch manually the URI segment or have it passed automatically to the controller's method, as usually happens.
You say "am a newb learning from nettuts" , but still say that Ellislabs doesn't know what it's doing; altough lightweight and far from perfect CI has a solid community, is actively developed and its general consensus is quite high; and if it decides to have the Active Record the way it is, there's a reason.
Also, consider that other more proper and real ORMs, like Propel or Doctrine, use a similar style in running queries (and you can use them too, instead of AR if you like it), taking advantage of PHP5 concatenation. An example taken right from the frontpage of propel:
$books = BookQuery::create() // retrieve all books...
->filterByPublishYear(2009) // ... published in 2009
->orderByTitle() // ... ordered by title
->joinWith('Book.Author') // ... with their author
->find();
So I see nothing strange in the way CI's Active Record is implemented or structured. If your code is not running, please give more details, like error codes and so on, so we can actually understand why it's not working.
IMPORTANT:
I just read the changelog from the latest version; try downloading it (version 2.10), as they state:
Added a PDO driver to the Database driver.

You're not gaining anything by using CI's DB class if you're not using ActiveRecord or the other functions. Why not just use PDO natively?
By the way, you could do the exact same thing this way:
$result = $this->db->
select(array('column1', 'column2'))->
where(array(
'column1' => $this->input->get('value'),
'column2' => $this->input->get('something')
))->get('table')->result();
print_r($result);

Related

PHP/mysql: Is changing (SELECT, {resource}) to ({resource}, SELECT) a viable temporary patch for mysql_* to mysqli_*?

On first inspection of the differences in application of the mysql*() and mysqli*() families of functions, it appears to me that
$seta = mysql_query("SELECT * FROM table WHERE field = $Filter", $database);
Can be rapidly replaced with:
$seta = mysqli_query($database, "SELECT * FROM table WHERE field = $Filter");
Similarly, it also appears that
IF ($A = mysql_fetch_array($seta)) {
do {
//code here
} while ($A = mysql_fetch_array($seta));
}
Could be replaced with:
IF ($A = mysqli_fetch_array($seta)) {
do {
//code here
} while ($A = mysqli_fetch_array($seta));
}
Will this work the way I am expecting it to? As it worked before mysqli*()?
PLEASE NOTE: I am not asking if I SHOULD do this, only if I CAN do this. I know full well that slapping a band-aid on a broken leg is useless... That said, I don't have that many hours of coding/testing time before the Demo in March this is being prepped for.
Yes, I understand the this is vulnerable code. I won't go to production without safeguards. I also realize that I am not using all the power of the mysqli*() family of functions this way.
My goal is to refactor everything properly when there isn't such a heavy time crunch (Yes, I know, famous last programmer words). I just need the patched code to run for a Demo then I can retire it.
I have high hopes that with a working prototype -- both in situ and on a server I'm spinning up just to demonstrate the need for software updates -- I'll be able to leave the PHP v4.x blues behind.
Project:
PHP/MySQL better user searching
Also checked:
How to upgrade from mysql* to mysqli*?
PHP Migrating from mysql* to mysqli
Above titles were trimed of underscores to prevent formatting
The quick and dirty method, with emphasis on dirty, is to do it this way by converting mysql_query to mysqli_query and so on. The problem is mysql_query is really clunky to use so preserving that coding style is not going to help clean anything up.
Although I'd strongly recommend switching to PDO, it's a more flexible and capable database layer, if you want mysqli then what you want to do is employ parameterized queries and bind_param to add user data to your query. This solves the vast majority of SQL injection bugs out of the gate. I'd also suggest using the object-oriented interface so your updated code is obvious. The difference of a single i can be easy to overlook, plus it's typically less verbose.
In other words, your replaced code looks like:
$stmt = $database->prepare("SELECT * FROM table WHERE field=?");
$stmt->bind_param('s', $filter);
$res = $stmt->execute();
If you're disciplined about doing this you should catch all your SQL mistakes.
PDO is nicer because of named parameters:
$stmt = $database->prepare("SELECT * FROM table WHERE field=:filter");
$res = $stmt->execute(array('filter' => $filter));
That usually means less code in the long-run.

Are prepared statements necessary FOR ME?

I always check/limit/cleanup the user variables I use in database queries
Like so:
$pageid = preg_replace('/[^a-z0-9_]+/i', '', $urlpagequery); // urlpagequery comes from a GET var
$sql = 'SELECT something FROM sometable WHERE pageid = "'.$pageid.'" LIMIT 1';
$stmt = $conn->query($sql);
if ($stmt && $stmt->num_rows > 0) {
$row = $stmt->fetch_assoc();
// do something with the database content
}
I don't see how using prepared statements or further escaping improves anything in that scenario? Injection seems impossible here, no?
I have tried messing with prepared statements.. and I kind of see the point, even though it takes much more time and thinking (sssiissisis etc.) to code even just half-simple queries.
But as I always cleanup the user input before DB interaction, it seems unnecessary
Can you enlighten me?
You will be better off using prepared statement consistently.
Regular expressions are only a partial solution, but not as convenient or as versatile. If your variables don't fit a pattern that can be filtered with a regular expression, then you can't use them.
All the "ssisiisisis" stuff is an artifact of Mysqli, which IMHO is needlessly confusing.
I use PDO instead:
$sql = 'SELECT something FROM sometable WHERE pageid = ? LIMIT 1';
$stmt = $conn->prepare($sql);
$stmt->execute(array($pageid));
See? No need for regexp filtering. No need for quoting or breaking up the string with . between the concatenated parts.
It's easy in PDO to pass an array of variables, then you don't have to do tedious variable-binding code.
PDO also supports named parameters, which can be handy if you have an associative array of values:
$params = array("pageid"=>123, "user"=>"Bill");
$sql = 'SELECT something FROM sometable WHERE pageid = :pageid AND user = :user LIMIT 1';
$stmt = $conn->prepare($sql);
$stmt->execute($params);
If you enable PDO exceptions, you don't need to test whether the query succeeds. You'll know if it fails because the exception is thrown (FWIW, you can enable exceptions in Mysqli too).
You don't need to test for num_rows(), just put the fetching in a while loop. If there are no rows to fetch, then the loop stops immediately. If there's just one row, then it loops one iteration.
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// do something with the database content
}
Prepared statements are easier and more flexible than filtering and string-concatenation, and in some cases they are faster than plain query() calls.
The question would be how you defined "improve" in this context. In this situation I would say that it makes no difference to the functionality of the code.
So what is the difference to you? You say that this is easier and faster for you to write. That might be the case but is only a matter of training. Once you're used to prepared statements, you will write them just as fast.
The difference to other programmers? The moment you share this code, it will be difficult for the other person to fully understand as prepared statements are kind of standard (or in a perfect world would be). So by using something else it makes it in fact harder to understand for others.
Talking more about this little piece of code makes no sense, as in fact it doesn't matter, it's only one very simple statement. But imagine you write a larger script, which will be easier to read and modify in the future?
$id = //validate int
$name = //validate string
$sometext = //validate string with special rules
$sql = 'SELECT .. FROM foo WHERE foo.id = '.$id.' AND name="'.$name.'" AND sometext LIKE "%'.$sometext.'%"';
You will always need to ask yourself: Did I properly validate all the variables I am using? Did I make a mistake?
Whereas when you use code like this
$sql = $db->prepare('SELECT .. FROM foo WHERE foo.id = :id AND name=":name" AND sometext LIKE "%:sometext%"');
$sql->bind(array(
':id' => $id,
':name' => $name,
':sometext' => $sometext,
));
No need to worry if you done everything right because PHP will take care of this for you.
Of course this isn't a complex query as well, but having multiple variables should demonstrate my point.
So my final answer is: If you are the perfect programmer who never forgets or makes mistakes and work alone, do as you like. But if you're not, I would suggest using standards as they exist for a reason. It is not that you cannot properly validate all variables, but that you should not need to.
Prepared statements can sometimes be faster. But from the way you ask the question I would assume that you are in no need of them.
So how much extra performance can you get by using prepared statements ? Results can vary. In certain cases I’ve seen 5x+ performance improvements when really large amounts of data needed to be retrieved from localhost – data conversion can really take most of the time in this case. It could also reduce performance in certain cases because if you execute query only once extra round trip to the server will be required, or because query cache does not work.
Brought to you faster by http://www.mysqlperformanceblog.com/
I don't see how using prepared statements or further escaping improves anything in that scenario?
You're right it doesn't.
P.S. I down voted your question because there seems little research made before you asked.

PDO... Am I doing it right?

So honestly, this is the first time I am working with PDO and Error Exceptions. I have gone thru manuals as well as different Q/As resolved here in past and came up with code that I am pretty satisfied with. But I really really need your opinion on this. I have built few functions that I normally use often in my projects.
Please note that right now I am doing a test project just intended to learn these 2 new things.
First of all, I am not a fan of OOP and have always preferred procedural programming type.
function _database_row($_table, $_id = 0, $_key = "id") {
global $Database;
if(is_object($Database)) {
$Query = $Database->prepare("SELECT * FROM {$_table} WHERE {$_key} = :id");
if($Query->execute(Array(":id" => $_id))) {
$Query_Data = $Query->fetchAll(PDO::FETCH_ASSOC);
if(count($Query_Data) >= 1) {
if(count($Query_Data) == 1) {
return $Query_Data[0];
}
return $Query_Data;
}
} else {
throw new Exception("Database Query Failure: ".$Query->errorInfo()[2]);
}
}
return false;
}
the above function is intended to fetch a row from $_table table with $_id (not necessarily an integer value).
Please note that $_id may (sometimes) be the only thing (for this function) that is fetched from $_REQUEST. By simply preparing the statement, am I totally secure from any SQL injection threat?
I couldn't find an alternative to mysql_num_rows() (I indeed found few PDO methods to use fetchColumn while using COUNT() in the query. But I didn't prefer it that way, so I want to know if I did it right?
also before people ask, let me explain that in above function I designed it so it returns the row directly whenever I am looking for a single one (it will always be the case when I use "id" as $_key because its PRIMARY auto_increment in database), while in rare cases I will also need multiple results :) this seems to be working fine, just need your opinions.
example of use:
_database_row("user", 14); // fetch me the user having id # 14
_database_row("products", 2); // fetch me the user having id # 14
_database_row("products", "enabled", "status"); // fetch me all products with status enabled
...sometimes during procedural programming, I wouldn't like those nasty "uncaught exception" errors, instead I will simply prefer a bool(false). So I did it like this:
function __database_row($_table, $_id = 0, $_key = "id") {
try {
return _database_row($_table, $_id, $_key);
} catch (Exception $e) {
return false;
}
}
(don't miss the use of another leading "_"). This also seems to be working perfectly fine, so what's your opinion here?
IMPORTANT:
what is the use of "PDOStatement::closeCursor" exactly? I did read the manual but I am quite confused as I can call my functions as many times as I want and still get the desired/expected results but never "closed the cursor"
now... ENOUGH WITH SELECTS AND FETCHINGS :) lets talk about INSERTS
so I made this function to add multiple products in a single script execution and quickly.
function _add_product($_name, $_price = 0) {
global $Database;
if(is_object($Database)) {
$Query = $Database->prepare("INSERT INTO products (name, price) VALUES (:name, :price)");
$Query->execute(Array(":name" => $_name, ":price" => $_price));
if($Query->rowCount() >= 1) {
return $Database->lastInsertId();
} else {
throw new Exception("Database Query Failure: ".$Query->errorInfo()[2]);
}
}
return false;
}
This also seems to be working perfectly fine, but can I really rely on the method I used to get the ID of latest insert?
Thank you all!
There is a lot going on here, so I will try to answer specific questions and address some issues.
I am not a fan of OOP
Note that just because code has objects doesn't mean that it is object oriented. You can use PDO in a purely procedural style, and the presence of -> does not make it OOP. I wouldn't be scared of using PDO for this reason. If it makes you feel any better, you could use the procedural style mysqli instead, but I personally prefer PDO.
By simply preparing the statement, am I totally secure from any SQL injection threat?
No.
Consider $pdo->prepare("SELECT * FROM t1 WHERE col1 = $_POST[rightFromUser]"). This is a prepared statement, but it is still vulnerable to injection. Injection vulnerability has more to do with the queries themselves. If the statement is properly parameterized (e.g. you were using ? instead of $_POST), you would know longer be vulnerable. Your query:
SELECT * FROM {$_table} WHERE {$_key} = :id
actually is vulnerable because it has variables in it that can be injected. Although the query is vulnerable, it doesn't necessarily mean that the code is. Perhaps you have a whitelist on the table and column names and they are checked before the function is called. However the query is not portable by itself. I would suggest avoiding variables in queries at all -- even for table/column names. It's just a suggestion, though.
I couldn't find an alternative to mysql_num_rows()
There isn't one. Looking at the count of fetched results, using SELECT COUNT or looking at the table stats (for some engines) are surefire way to get the column count for SELECT statements. Note that PDOStatement::rowCount does work for SELECT with MySQL. However, it is not guaranteed to work with any database in particular according to the documentation. I will say that I've never had a problem using it to get the selected row count with MySQL.
There are similar comments regarding PDO::lastInsertId. I've never had a problem with that and MySQL either.
let me explain that in above function I designed it so it returns the row directly whenever I am looking for a single one
I would advise against this because you have to know about this functionality when using the function. It can be convenient at times, but I think it would be easier to handle the result of the function transparently. That is to say, you should not have to inspect the return value to discover its type and figure out how to handle it.
I wouldn't like those nasty "uncaught exception" errors
Exception swallowing is bad. You should allow exceptions to propagate and appropriately handle them.
Generally exceptions should not occur unless something catastrophic happens (MySQL error, unable to connect to the database, etc.) These errors should be very rare in production unless something legitimately happens to the server. You can display an error page to users, but at least make sure the exceptions are logged. During development, you probably want the exceptions to be as loud as possible so you can figure out exactly what to debug.
I also think that names should be reasonably descriptive, so two functions named __database_row and _database_row are really confusing.
IMPORTANT: what is the use of "PDOStatement::closeCursor" exactly?
I doubt you will have to use this, so don't worry too much about it. Essentially it allows you to fetch from separate prepared statements in parallel. For example:
$stmt1 = $pdo->prepare($query1);
$stmt2 = $pdo->prepare($query2);
$stmt1->execute();
$stmt1->fetch();
// You may need to do this before $stmt2->execute()
$stmt1->closeCursor();
$stmt2->fetch();
I could be wrong, but I don't think you need to do this for MySQL (i.e. you could call execute on both statements without calling closeCursor.
can I really rely on the method I used to get the ID of latest insert?
PDO's documentation on this (above) seems to be more forgiving about it than it is about rowCount and SELECT. I would use it with confidence for MySQL, but you can always just SELECT LAST_INSERT_ID().
Am I doing it right?
This is a difficult question to answer because there are so many possible definitions of right. Apparently your code is working and you are using PDO, so in a way you are. I do have some criticisms:
global $Database;
This creates a reliance on the declaration of a global $Database variable earlier in the script. Instead you should pass the database as an argument to the function. If you are an OOP fan, you could also make the database a property of the class that had this function as a method. In general you should avoid global state since it makes code harder to reuse and harder to test.
the above function is intended to fetch a row from $_table table with $_id
Rather than create a generic function for querying like this, it is better to design your application in a way that will allow you to run queries that serve specific purposes. I don't really see why you would want to select all columns for a table for a given ID. This is not as useful as it seems. Instead, you probably want to get specific columns from these tables, perhaps joined with other tables, to serve specific functions.
Well, your main problem is not OOP, but SQL.
To tell you truth, SQL is by no means a silly key-value storage you are taking it for. So, it makes your first function, that can be used only on too limited SQL subset, is totally useless.
Moreover, you are making a gibberish out of almost natural English of SQL. Compare these 2 sentences
SELECT * FROM products WHERE status = ?
quite comprehensible - isn't it?
products! enabled! status!
HUH?
Not to mention that this function is prone to SQL injection. So, you just have to get rid of it. If you want a one-liner, you can make something like this
function db_row($sql, $data = array(), $mode = PDO::FETCH_ASSOC) {
global $Database;
$stmt = $Database->prepare($sql);
$stmt->execute($data);
return $stmt->fetch($mode);
}
to be called this way:
$row = db_row("SELECT * FROM products WHERE id = ?",[14]);
Note that PDO is intelligent enough to report you errors without any intervention. All you need is set it into exception mode.
Speaking of second function, can be reviewed.
function _add_product($_name, $_price = 0)
{
global $Database;
$sql = "INSERT INTO products (name, price) VALUES (?,?)";
$Database->prepare($sql)->execute(func_get_args());
return $Database->lastInsertId();
}
is all you actually need.
I couldn't find an alternative to mysql_num_rows()
You actually never needed it with mysql and would never need with PDO either

How do you escape ' on doctrine?

How do you escape ' on doctrine?
I made this code
$query = $em->createQuery(
"SELECT a FROM AcmeTopBundle:ArtData a WHERE
a.name = '". mysql_escape_string($name) ."'");
but when the $name is A'z
it returns error
[Doctrine\ORM\Query\QueryException]
SELECT a FROM AcmeTopBundle:ArtData a WHERE
a.name = 'A\'s'
I think I escaped by mysql_escape_string in case of using raw sql.
How can I avoid this error on doctrine?
The way I usually handle this is using parameters and querybuilder (https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html)...
$qb = $em->createQueryBuilder(
"SELECT a FROM AcmeTopBundle:ArtData a WHERE
a.name = :name")
->setParameter('name',$name);
$result = $qb->getQuery()->execute();
Well, even though there is accepted answer it is not for question as it is in title.
#Sven's answer comes close, but fails to mention:
Doctrine documentation
To escape user input in those scenarios use the Connection#quote() method.
And I have a gripe with "scenarios", or more with people pushing prepared statements like some holy grail. Well they are nice in theory, in practice at least in PHP they are quite shity, as they are unable to do simple stuff like IN (<list>) or multi inserts with VALUES (<bla bla>), (<more stuff>) which is a huge ass deal, as without it one ends up resorting to quite sub-optimal SQL (to put it lightly) quite commonly (well if one religiously insist on prepared statements at least).
This does not answer your question, but explains what's wrong with your code. It didn't fit into a comment.
You cannot and should not use mysql_escape_string()
It is the wrong escape function, the right one used to be mysql_real_escape_string(). Reading the documentation does not sound like it, but to properly escape, you have to know which character encoding is being used. In western encoding schemes like ASCII, ISO-8859-x or even UTF-8 it probably does not make a difference, but there are some exotic chinese encodings around which absolutely need to know whether that " byte belongs to another byte, or comes on it's own.
When using mysql_real_escape_string(), you need to have an already open DB connection created with mysql_connect(). If you don't, PHP tries to open a new connection with default user and password as defined in the php.ini file. This usually results in an error because without password the database won't let you do anything. And additionally, if you have success, then the encoding setting of this connection most likely is not the one used by Doctrine.
Using any of the mysql_* functions is wrong, because these are deprecated. The correct way would be to use mysqli_* functions.
Doctrine may use any of the three database connection methods: mysql, mysqli or PDO. You have to choose the one really being used if you want to manually call the correct escaping function. While the connection is already created. And somehow you need to grab that connection resource to allow the function you are calling to detect the used encoding.
So in the end there are plenty of reasons why it is wrong to just use any escaping that sound like it is doing the job.
The right way is to use the escaping of the database layer you are using. If you use Doctrine, the use it for escaping. Or better, avoid escaping, use prepared statements or the query builder and let Doctrine deal with the rest.
Based on https://stackoverflow.com/a/13377430/829533
you can use prepared statements http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#using-prepared-statements
From the documentation:
$date = new \DateTime("2011-03-05 14:00:21");
$stmt = $conn->prepare("SELECT * FROM articles WHERE publish_date > ?");
$stmt->bindValue(1, $date, "datetime");
$stmt->execute();
This will show how to insert the data into the database where you would normally have to use real_escape_string.
Doctrine and Symfony 3 using prepared not QueryBuilder:
// get the post value
$value = $request->request->get('value');
$sql = "INSERT INTO `table_name`
(`column_name1`,`column_name2`)
VALUES
('Static Data',?)
";
$em = $this->getDoctrine()->getManager();
$result = $em->getConnection()->prepare($sql);
$result->bindValue(1, $value);
$result->execute();
Now for a bonus to get a success/fail if you are using auto increment records:
$id = $em->getConnection()->lastInsertId();
if $id has a value then it executed the insert. If it does not the insert failed.

What PDO function is equal to db::getOne

I am wondering what PDO function that is equal to the db::getOne?
I have this i need to change to PDO:
$count = db::getOne($query,$id,$showU['id']);
$st = $pdodb->prepare($query);
$st->bindValue('id', $id);
$count = $st->fetchColumn();
This assumes you use named parameters which are always better than positional parameters IMO.
You really need to provide more info but im going to assume that id and $showU['id'] are params to be bound to $query and that getOne retruns a single record. If these assumptions are correct you would do something like:
$query = "SELECT count(id) as nb_records FROM your_table_name WHERE id = :id AND uID = :uid";
$stmt = $pdo->prepare($query);
$stmt->execute(array(':id' => $id, ':uid' => $showU['id']);
$count = $stmt->fetchColumn();
You could of course chain these.
It's a user-defined function. One can use not only ready-made functions, but also create new ones. So, getOne is of this kind. It has nothing to do with PDO or other library. It's rather of your own library. But of course, it can be made by using PDO as well.
You can adopt this function to make a similar one which returns scalar value instead of array. But it seems you do not quite understand the meaning and the benefits (no offense - it's just matter of experience), so, nevermind. This function is not obligatory, it's just to make your code shorter and cleaner.
Programming, in general, stands for eliminating repetitions. Most of local folks aren't programmers but rather copy/pasters. Most of them just don't care of code size or readability. Not quite bad, as long as their code works. So, you can go this way too.
The only purpose of this function is to do less work for you and make your code more readable. It doesn't affect any results. So, it's not obligatory.

Categories