So, if I want to pull some data from my database (PHP, MySql), whether I'm writing for a class or hard-coded, I've been doing something along the lines of:
$x = "SELECT <column(s)> FROM <table> WHERE <conditions>";
$y = mysql_query($x);
while($result = mysql_fetch_assoc($y))
{
echo $result['column']; // etc
}
Obviously I use a function or class (depending on design pattern) so pulling data like this is done in one line, I just wondered if I was doing 'too much work' and if there was a quicker way of doing this.
Thanks.
You can get tighter code by using a more up-to-date PHP module to access your database.
The mysql_xxx() functions that you're using have been superseded by the mysqli_xxx() functions. This uses similar code, but provide more features and security than the older library:
$query = 'SELECT <column(s)> FROM <table> WHERE <conditions>';
if ($result = $mysqli->query($query)) {
while ($row = $result->fetch_assoc()) {
print $row['column'];
}
}
You can find out more about MySQLi (including how it differs from the old MySQL library) here: http://php.net/manual/en/book.mysqli.php
But for really concise code, you might consider looking into the PDO library. Your query could be expressed with PDO like this:
$sql = 'SELECT <column(s)> FROM <table> WHERE <conditions>';
foreach ($conn->query($sql) as $row) {
print $row['column'];
}
...and if you really wanted to, the first two lines of that code could be combined as well.
Find out more about PDO at the PHP manual site: http://www.php.net/manual/en/book.pdo.php
Looks good. you maybe can merge the first tow lines into "$y = mysql_query('SELECT FROM WHERE ');"
And notice that in PHP its faster (from compile time) to use single quotes (') rather that double quotes (").
It depends on the further work, but you might wanna consider loading the info into XML dom format. (If you want to do more sophisticated things that just representing the data)
Related
I've gotten into the habit of writing the following sort of code:
$q = mysqli_query($mysqli,"SELECT * FROM table WHERE a='$a', b=$b;");
while ($row = mysqli_fetch_array($q)) {
// do something
}
Where $a is a string entered by the user (gotten through $_GET) and $b is a user-entered integer.
Obviously the code I have above is vulnerable to SQL injection attacks, so my habit is to rewrite it like this:
$q = mysqli_query($mysqli,"SELECT * FROM table WHERE a='".str_replace("'","",$a)."', b=".($b+0).";");
But this of course has problems if $a needs to have apostrophes (or quotation marks when quotation marks are used to mark the string).
Recently I learned about prepared statements in mysqli and started playing around with them. I wrote the following function to make it easier to make calls without having to change much of my code:
function safequery($a,$b,$c) {
global $mysqli;
$q = mysqli_prepare($mysqli,$a);
$e = "mysqli_stmt_bind_param(\$q,\$b";
$i = 0;
while ($i < count($c)) {
$e.=",";
$e.="\$c[$i]";
$i++;
}
$e.=");";
eval($e);
mysqli_stmt_execute($q);
return $q;
}
safequery("SELECT * FROM table WHERE a=? AND b=?;","si",array("unsafestring",37));
But what is returned from this function turns out not to be a mysqli_result and thus doesn't work with the first bit of code above. After some more research, I found an alternative, but it would require a complete rethink of how I write my code. Is this necessary or is it possible to protect against MySQL injection attacks with only small changes to the first bit of code (no new lines, same output style, etc.)?
I have looked around on StackOverflow and the rest of the web but I can't find a good simple solution; all of them require the edition of at least three more lines for every call and a different way of reading each row. I'd prefer to do this procedural-y...
Don't think half-measures are going to solve this problem. Commit to expunging all of the interpolation bugs from your code and be disciplined about using prepared statements. Your proposed fix only makes things worse, it gives you a false sense of security. It's also considerably more work than using prepared statements so I'm not sure why you'd even bother doing it this way.
One way to make this a lot easier to do is switch from using double quotes " to single quotes ' on your queries to disable interpolation. Any escaping errors become syntax problems, and if your editor highlights those you'll be able to spot them from across the room, and if something does by fluke work you'll be inserting harmless things like $a instead of actual data.
Another thing to consider is if you should be using an ORM like Doctrine or Propel given what you know about the sophistication of your application. These can make things considerably easier from an implementation perspective.
The code you have there is a ticking time bomb, get rid of it as soon as you can. Don't think replacing quotes is enough, that solves just one issue, there's actually a number of other methods your application can be vulnerable to injection bugs. Tools like SQLMap have an entire arsenal of things they can try to break your code and if you look at the list of things it can do if it finds a flaw you'll probably want to fix these problems right away.
One way you can find issues is using a tool like grep:
grep query `find -name '*.php'` | grep '\$'
That's not bulletproof, but it should probably turn up a lot of code you should fix right away.
Also as #ceejayoz suggests, purge that function with eval in it from your computer and never, ever do that again.
After talking with the commenters and looking at some of the other questions and things they linked to and suggested, I've rewritten the third code snippet to both solve the problem in question and fix the security holes that several commenters pointed out (if there are any remaining ones, please tell me).
First on my use of eval(). Though I can't see any immediate way it could cause problems (user strings are not executed as code in the eval()) it is certainly a round about and stupid way of solving my problem. #TadMan suggested call_user_func_array() which, once worked out, looks something like this:
function refValues($arr){
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}
function safequery($a,$b,$c) {
global $mysqli;
$q = mysqli_prepare($mysqli,$a);
call_user_func_array("mysqli_stmt_bind_param",refValues(array_merge(array($q,$b),$c)));
mysqli_stmt_execute($q);
return $q;
}
safequery("SELECT * FROM table WHERE a=? AND b=?;","si",array("unsafestring",37));
It turns out that mysqli_stmt_bind_param() takes only references, thus the new refValues() function (run into and solved before on StackOverflow: https://stackoverflow.com/a/16120923/5931472).
While this removes eval() and makes my code easier to understand, it still doesn't solve the original problem of returning the query response in a way that mysqli_fetch_array() can use. It turns out that the proper function to do this is mysqli_stmt_get_result() so the last line of safequery() is rewritten from:
return $q;
To:
return mysqli_stmt_get_result($q);
The result of safequery() is then a mysqli_result which can be used by mysqli_fetch_array().
Which one of these two is better in my case?
While loop:
function search_hotel($searchterm)
{
$query = $this->db->order_by("id", "desc")->like('name', $searchterm)->get('hotel_submits');
$data = array();
while($row = mysql_fetch_array($query))
{
$data[] = $row->name;
}
return $data;
}
Foreach loop:
function search_hotel($searchterm)
{
$query = $this->db->order_by("id", "desc")->like('name', $searchterm)->get('hotel_submits');
$data = array();
foreach ($query->result() as $row)
{
$data[] = $row->name;
}
return $data;
//return mysql_query("select * from hotel_submits where name LIKE '".$searchterm."'");
}
while is technically more efficient than foreach, but it's not worth comparing: they're both pretty much identical in this case.
In your case, result returned by query is array. Which means you can use foreach statement or while statement.
Just note that foreach statement is optimized for working with arrays (and as of PHP5, objects as well) and is faster than while statement. While can be used to achieve the same effect but it is not as efficient if you want to go through all elements of the array.
When using a framework and its custom DB adapter class, it seems pointless to switch back to PHP's built-in functions in the middle of a script. Even if CI's adapter and PHP's mysql_* functions might be using the same DBMS connection library (mysql).
I strongly recommend to stick with Code Igniter's version (foreach ($query->result() as $row)). From a performance point of view, there shouldn't be any noticeable differences. Regarding the application architecture, it certainly is much cleaner not to mix the access interfaces. Although it might work out, it might also cause problems.
It would appear you're mixing up mysqli and mysql syntax. The two libraries are NOT compatible internally. You cannot use a handle/statement in one and consume it in another. Both libraries maintain completely independent connections to the database.
That'd mean the first one will be faster, since mysql_fetch_array() will fail and the inner loop will never run. But faster doesn't mean "right".
i got this code
while ($aResult = mysql_fetch_array($result))
{
$sResult[$aResult[userID]] = $aResult;
}
but i want to know is there a faster way to put everything from $aresult in the sresult global?
It depends on the definition of "faster". If you want minimum CPU usage, you propably should use the function above, or as Col. said, try to avoid fetching all and use pointers.
If you want less coding time, consider using a a wrapper such as PEAR DB. With it you can just write $res = $db->getAll( $SQL );
http://pear.php.net/manual/en/package.database.db.db-common.getall.php
Are there any great, lightweight MySQL connection classes out there for PHP that anyone recommends?
I have written my own, and I do think it is pretty good but this seems like the sort of thing that many programmers better than me must have perfected long ago.
I'm interested in finding something that I can slot in generically and use as I need it with as little hassle as possible.
Some generic functions to support querying, connecting to multiple MySQL databases within the one application would also be a plus.
Have you had a look at PDO? http://php.net/manual/en/book.pdo.php
PHP's PDO (PHP Data Objects) extension is my recommendation. I use it alongside a light-weight database class that extends PDO. You can find this open-source project on Google's Project Hosting at http://code.google.com/p/php-pdo-wrapper-class.
A class of my own invention: DB
It may be called very lightweight (less than 100 lines of code). It is a wrapper around PDO and it actually only adds a very handy way of escaping variables and a short syntax (DB::query() instead of DB::instance()->query().)
But this short syntax results in it being limited to once connection.
The simplest and lightweight db class is
http://code.google.com/p/edb-php-class/
<?php
$result = $db->q("select * from `users`limit 3");
foreach($result as $a){
$a = (object) $a;
echo $a->id.' '.$a->name.' '.$a->url.' '.$a->img.'</br>';
}
$result = $db->line("select * from `users` where id = '300' limit 1");
echo $result['name'];
echo $result['surname'];
$name = $db->one("select name from `ilike_pics` where id = '300' limit 1");
echo $name;
?>
this is a very neat and easy to use class: http://justinvincent.com/ezsql
wordpress database class is also derived from the above class
May try ADOdb and ADOdb Lite
So I have this database class in PHP and I only have 1 function in it (other than __construct and __destruct. Let me explain further...
I had originally written it so when I connected to a database I would just call my function connect_to_db() which returned a mysqli object. I then used this objects functions (->query(), ->prepare(), ->bind_param(), et cetera..) to do whatever. This cluttered (and still is as I haven't switched my code over to my new class yet) with a lot of functions that just do specific things, for example:
function get_country_info($db, $usrid) {
$statement = "select `name`, `population`, `money`, `food` from `countries` where `usr_id` = ?";
$qry = $db->prepare($statement) or
trigger_error("get_country_info():statement failed...");
$qry->bind_param("i", $usrid);
$qry->execute();
$qry->bind_result($name, $population, $money, $food);
$qry->fetch();
$res = array("name" => $name,
"pop" => $population,
"money" => $money,
"food" => $food);
return $res;
}
And what I originally planned to do was just to throw these into a class for clarity, but what I actually ended up doing was creating a class that when created creates a mysqli object for a specific database (supplied via an argument) and when destroyed closes off this link. I very much like not having to worry about typing $db->close(); as when the script finishes executing the connection is closed.
It only has 1 other function; query(). This function can handle any query put forth and outputs it as a multidimensional array. It uses eval(). From what I understand this is generally frowned upon - but eval() is so useful; so why is it frowned upon?
I guess the function may be slow, but seen as I'm just using it for a pet project (browser based country management game) and I haven't noticed anything I'm not worried about that at all. What I am worried about is whether people would generally do this in the 'real world' or whether there is some sort of standard by which people do this, or perhaps something included (or add-on-able) in PHP which is usually used?
I'm self taught, so sometimes I don't really know the best way to go about doing things. Perhaps somebody could advise me here?
The function in question can be seen here: http://pastebin.org/353721, as its ~60 lines and I don't want to clutter the page. I also haven't extensively tested it (I don't even know what unit tests are, so I test by using the function in a lot of different ways) so it may have problems I'm not aware of that you guys can point out.
Thanks.
Doesn't seem to me too bad. You have basically done a really basic wrapper around the database, and you performed the very first step in database independence, which is good.
This can be good for small and well organized projects, but once you will start going more complicated, you will soon notice that your approach has one large disadvantage: you still have your SQL queries split around the site. The day you will change anything in the database, you'll need to go through all your site and look for all the SQL statements: this is bad (I had to do it once...).
You should now move all the SQL code to one place. So there are various options. In a similar context, I made the query() method protected, then made the Db class "abstract" and subclassed it. Each subclass is a class which contains several methods relative to a specific set of tables, and this is the only place where you find SQL. All the rest of the project can only call these methods.
Or, even better, you could use an ORM (oblect relational mapper) which would map each table to an object.
For what concerns the evils of evals: I never used them. But I thought I wasn't going to use a "goto" because it's evil, and then I found the magic place where that was the perfect fit. So, if you have investigated all the possibilities, and you think that's the optimal solution... use it.
Instead of eval, you can use call_user_func() or call_user_func_array().
You should check the return value of execute().
Your function does not support subselects which contain multiple comma's, but only return one value.
You can use trim() instead of ltrim(rtrim()).
I would still use a function like get_country_info() on top of this db class. Often, you want to do something with the data before your application can use it. More importantly, you want to abstract the data storage from your application. That is, the method which uses the country info does not need to know that it came from the database.
As Techpriester wrote: brake it down into smaller parts.
I recommend at least:
the argument to bind converter
the single and multi param bind if-else branch
the sql statement parser (find out about returned fields)
One other approach to your problem would be to build the sql statement inside your query class (arguments would be field names, the table, the where constraints,... ) and to develop subclasses for different query types. This would elimiate the need to parse the statement.
Above this layer you would put a bunch of DAO classes to do the actual work.
But wait: others have done this... (maybe a lot of others to be specific). So using PDO, Doctrine, Propel or even a bigger library like ZendFramework (active record pattern there...) would be the most valuable and stable option.
If you, however, want to learn something about software architecture and OO Systems. Go ahead and build your own, if you do it well you can switch to another DB Layer as soon as your system grows (Version 2.x :-) ).
First: The eval() in your function doesn't serve any purpose as I see it. Why don't you call the $qry->... things directly?
Second, your function is way to complex. Brake it down into smaller parts that call each other.
Third: Manipulating SQL Statements is generally a very bad idea. It's error prone as soon as you feed your function with something like nested statements or other more complicated SQL code. So just don't do it.
Fourth: I wouldn't recommend using mysqli anymore. You should switch to PDO.
As I understand it, your function tries to find out, what fields were in the SELECT clause of the query to build the result array. That is only necessary if you want to allow your database layer it to execute arbitrary queries which is also not a good idea.
When I have to use classic SQL in an application, I predefine every query that I need in some method or function. That function then will know exactly what field it has to read from the result set. So there's no need to parse the SQL code. However, mostly I try to avoid SQL by using things like Doctrine ORM. SQL is just too prone to errors...
About eval(): It is entirely and absolutely evil for several reasons:
It may open the door to code injection.
It makes code unreadable to humans and unparsable to an IDE
It's nearly impossible to debug code that uses eval()
Not really a problem of eval() itself, but when you have to use it, that's a sign of a flawed design.
To your question - you need some experience to learn why there are "best practices", why eval() is deprecated, why people use prepared statements etc.
I'd recommend you to have a look at http://dibiphp.com/cs/ for a nice and concise DB layer for PHP.
You could also try Java when you get some clue about web technologies.
Then you can use cool things like iBatis, which almost got it to PHP
I personally once had a lib for DB, which was used like this:
$aasAreas = Array();
$sSQL = "SELECT id, x, y, x2 AS r, popis FROM ".$oFW->GetOption('tables.areas')
." WHERE id_ad=".asq((int)$_GET['id']);
$oRes = $oFW->GetDB()->Select($sSQL);
if(!$oRes || !$oRes->IsOk()){ $sError = $oRes->GetError(); break; }
else while( $a = $oRes->FetchRow() ){
$aasAreas[] = $a;
}
[OT] And some ORM for PHP attempt, used like this:
// Load by ID
echo "<h3>Load by ID</h3>";
$iID = 1;
echo "<pre>\$oObject = \$oOP->LoadObjectById(".$oClass->GetName().", $iID);</pre>";
$oUser = $oOP->LoadObjectById($oClass, $iID);
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Save
echo "<h3>Save</h3>";
$oUser = new cObjectPersistenceTestClass_User();
$oUser->SetId(1);
$oUser->SetProperty('user', 'as'.rand());
$oUser->SetProperty('pass', 'as');
$oUser->SetProperty('fname', 'Astar');
$oUser->SetProperty('lname', 'Seran');
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
$bSucc = $oOP->SaveObject($oUser);
echo "<div>".($bSucc ? 'saved' : 'error')."</div>";
// Load by value - load object created above -> Object Pool hit
$xVal = $oUser->GetProperty('user');
$aoUsers = $oOP->LoadObjectsByValue($oClass, 'user', $xVal);
echo "<pre>\$aoUsers: [".gettype($aoUsers)."]".AdjustedPrintR($aoUsers)."</pre>";
etc.