would it be safe to use functions to access database values? - php

I am pretty new with PHP furthermore PDO so I am not fully aware of what to avoid (and include) when accessing databases apart from SQL injection. (FYI, in the example below the table "users" also include passwords), however would accessing the database using a function as below to get information from be safe? is it prone to attacks?
and if you don't understand why I've done this it's because I find it quicker and it will make it easier when linking tables :)
<?php
require("access/common.php");
function getval($username, $column, $table, $datab){
$query = "
SELECT
id,
username,
email
FROM ".$table."
WHERE
username = :username
";
$query_params = array(
':username' => $username,
);
try
{
$stmt = $datab->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
die();
}
$row = $stmt->fetch();
if($row)
{
return $row[$column];
}
}
echo getval("USERNAME", "email", "users", $db);
?>

The question you ask is very open-ended. Your biggest vector for attack is always what you do with user input (anything that a user can submit to your application/website through $_GET or $_POST variables). Certainly there are not security threats with the PHP language constructs eg. functions.
In your example I can see that you are binding the ":username" parameter but not the ":table" parameter which might be a vector for injection if you accept unsanitized user input and use it as the "$table" value.
Always be careful how your use $_GET and $_POST values... and when this becomes tedious, look for a framework to make some of this automatic.

A function is no safer or less safe than code outside of a function. If it's something you're going to be using more than once or twice, definitely put it in a function. As long as you're using PDO properly you'll be fine.
That said, you might want to put all your database functions in a class, then instantiate a $db object of that class, from which you can then call any database functions you need. There's lots of ways to organize your code to make things easier to work with.

Related

Php function for last login is not working,

Got a problem when creating a function/procedure to write the user's last login.
The query works standalone since I used to copy and paste this code into several pages, instead of that, I went for creating a whole new PHP file called functions.php where I store all of my functions.
The thing is that I created the function with the same code I had working before but still, I can't get it to work by just simply calling it.
Variable $connection has a mysqli_connect() function in order to create a connection with the database. This one is stored in an independent file.
function last_login(){
$login = "UPDATE users SET last_log=NOW() WHERE user='".$user."'";
mysqli_query($connection, $login);
}
last_login();
I tried using
return = mysqli_query($connection, $login);
to return a value into a normal $variable so I can output that on the other file, but nothing changed.
Also, to prove that there was a connection between these two files, created a new function containing an echo "lol world"; a single line, it indeed worked, so there I guess there is no problem there.
You need to pass in the variables for the connection and the user.
MySQL will store the number of seconds since 1 Jan 1970. And calculate the difference. Also you can use LOCALTIME() function to get the current date and time as follows.
function last_login($connection, $user){
$login = "UPDATE `users` SET `last_log` = LOCALTIME() WHERE `user` ='$user'";
mysqli_query($connection, $login);
}
last_login($connection, $user);
Make sure the column last_log is timestamp and not date. You need to avoid SQL injection by using prepared statements. Also for more debugging of code use mysqli_error() function to know the exact error.
You need to pass the variables $connection and $user as arguments to your function.
// Define function which accepts 2 parameters
function last_login(mysqli $connection, string $user) {
$stmt = $connection->prepare('UPDATE users SET last_log=NOW() WHERE user=?');
$stmt->bind_param('s', $user);
$stmt->execute();
}
// When calling the function pass the variables as arguments
last_login($connection, $user);
Pay attention to the fact that I used prepared statements. You should never inject variables into SQL queries, this could lead to broken code and leave you vulnerable to SQL injection.

Passing $_POST/$_GET as a parameter to function

I came across an interesting piece of PHP code which has me a bit stumped as to why the author has chosen to do this.
function do_something($db, $post_vars){
foreach($post_vars as $key => $value{
$vars[$key] = mysqli_real_escape_string($db, $value);
}
return $vars;
}
$db = mysqli_connect("myhost","myuser","mypassw","mybd") or die("Error " . mysqli_error($link));
do_something($db, $_POST);
It got me thinking about why someone would want to pass $_POST as a variable and just not access it directly inside the function? The only benefit I could think of (and this was a bit of a long shot) was if we were to append other information to $_POST before calling the function (such as):
function do_something($db, $post_vars){
foreach($post_vars as $key => $value{
$vars[$key] = mysqli_real_escape_string($db, $value);
}
return $vars;
}
$db = mysqli_connect("myhost","myuser","mypassw","mybd") or die("Error " . mysqli_error($link));
foreach($_POST as $post_key => $post_value){
$post[$post_key] = $post_value;
}
$post['my_custom_var'] = "a";
do_something($db, $post);
There is, however, no evidence of this practise anywhere in the code. Just calls to do_something() with $_POST being passed as an arugment.
My question then is, is there any benefit in doing it like this that I've missed or did the author simply not understand that $_POST is a global variable?
A complete long shot: Is there perhaps even any well intended "later additions" they could make to this (such as my example) that would almost justify this practise or is this just a case of misunderstanding. Or perhaps is there a security implication that could justify the practise?
IMHO it's a practice of abstraction, and there are benefits:
Generality: by receiving $_POST as a parameter, the function becomes less tightly coupled to $_POST. The function may serve more scenarios & possibly be more reusable.
Inversion of control: because the function's dependency($_POST) is injected from outside, you have more control over the function. It is a bit unlikely but let's suppose your form has been updated and now you need to submit via GET method. Without modifying the function's body, passing in $_GET on the caller's side, is enough to reflect the change.
Test fixture isolation: To mock FORM inputs to test a certain code path in the function, it is better access global states (such as $_POST) in an abstracted way, so that the test itself does not bring side effects to other part of the system.
In general, there is a very good reason to pass $_POST or $_GET or whatever array you want as argument instead of accessing it through the auto-global variables. It's called "dependency injection" and it's a key feature for testable code.
Another reason to not use auto-globals (or global variables, in general) is the readability of the code.
Compare:
function do_something($db, array $post_vars) {
// many lines of code here, you don't want to read them
}
do_something($db, $_POST);
with
function do_something_else($db) {
// many lines of code here that use $_POST, you don't want to read them either
}
do_something_else($db);
In the first case its clear that function do_something() operates over the values of $_POST (or $_GET or whatever other array full of data you pass it as argument). You don't have to read the function's code to know that; all the relevant information is displayed in the function header and in the example usage.
In the second case, the behaviour of function do_something_else() depends on the content of $_POST but one cannot know this without looking at its code.
Back to the code you posted, it doesn't look like it was written having testability in mind.
Take a look only at:
foreach($_POST as $post_key => $post_value){
$post[$post_key] = $post_value;
}
It basically does $post = $_POST in more words.
It's a good idea to sanitize the $_POST Superglobal before passing it as an argument of a function, then escape it inside the function that has your query logic.
What he does is escaping every POST variable through mysqli_real_escape_string function, which makes sure you avoid SQL Injection attacks.Then he returns the array (with escaped values) by calling : return $vars;
He might have used a function to do this because he intends to repeat the steps several times throughout the application and he might just call that function and passing the variables instead of writing the code over and over again.
MAKE SURE YOU ALWAYS ESCAPE USER INPUT BEFORE MAKING ANY DATABASE CALLS.

Escape SQL queries in PHP PostgreSQL

I have a website with lots of PHP files (really a lot...), which use the pg_query and pg_exec functions which do not
escape the apostrophe in Postgre SQL queries.
However, for security reasons and the ability to store names with
apostrophe in my database I want to add an escaping mechanism for my database input. A possible solution is to go
through every PHP file and change the pg_query and pg_exec to use pg_query_params but it is both time consuming
and error prone. A good idea would be to somehow override the pg_query and pg_exec to wrapper functions that would
do the escaping without having to change any PHP file but in this case I guess I will have to change PHP function
definitions and recompile it which is not very ideal.
So, the question is open and any ideas that would
allow to do what I want with minimum time consumption are very welcome.
You post no code but I guess you have this:
$name = "O'Brian";
$result = pg_query($conn, "SELECT id FROM customer WHERE name='{$name}'");
... and you'd need to have this:
$name = "O'Brian";
$result = pg_query_params($conn, 'SELECT id FROM customer WHERE name=$1', array($name));
... but you think the task will consume an unreasonable amount of time.
While it's certainly complex, what alternatives do you have? You cannot override pg_query() but it'd be extremely simple to search and replace it for my_pg_query(). And now what? Your custom function will just see strings:
SELECT id FROM customer WHERE name='O'Brian'
SELECT id FROM customer WHERE name='foo' OR '1'='1'
Even if you manage to implement a bug-free SQL parser:
It won't work reliably with invalid SQL.
It won't be able to determine whether the query is the product of intentional SQL injection.
Just take it easy and fix queries one by one. It'll take time but possibly not as much as you think. Your app will be increasingly better as you progress.
This is a perfect example of when a database layer and associated API will save you loads of time. A good solution would be to make a DB class as a singleton, which you can instantiate from anywhere in your app. A simple set of wrapper functions will allow you to make all queries to the DB go through one point, so you can then alter the way they work very easily. You can also change from one DB to another, or from one DB vendor to another without touching the rest of the app.
The problem you are having with escaping is properly solved by using the PDO interface, instead of functions like pg_query(), which makes escaping unnecessary. Seeing as you'll have to alter everywhere in your app that uses the DB, you may as well refactor to use this pattern at the same time as it'll be the same amount of work.
class db_wrapper {
// Singleton stuff
private $instance;
private function __construct() {
// Connect to DB and store connection somewhere
}
public static function get_db() {
if (isset($instance)) {
return $instance;
}
return $instance = new db_wrapper();
}
// Public API
public function query($sql, array $vars) {
// Use PDO to connect to database and execute query
}
}
// Other parts of your app look like this:
function do_something() {
$db = db_wrapper::get_db();
$sql = "SELECT * FROM table1 WHERE column = :name";
$params = array('name' => 'valuename');
$result = $db->query($sql, $params);
// Use $result for something.
}

PHP Class best practices and class structures

I'm currently creating a simple CMS for my small website in PHP5. This is my first 'larger' project in PHP. First I'm creating the needed classes that would simplify me the work a little bit, and there I'm stuck. I need your opinions about the following function inside my UserInfo class:
public function setUser($id) {
if(!isset($id)) {
return false;
}
session_start();
$conn = new mysql($_SESSION['DBCONNINFO']);
$sql = "SELECT
usr.ID,
usr.USERNAME as TUSERNAME,
usr.FIRST_NAME,
usr.LAST_NAME,
usr.PHONE,
usr.MOBILE,
usr.EMAIL,
usr.ADDITIONAL_INFO,
usr.LAST_LOGIN_DATE,
usr.USER_GROUP_ID
FROM cms_users usr
WHERE usr.id = " . $id;
$result = $conn->query_cust($sql);
$conn=null;
foreach ($result as $row) {
$this->id = $row['usr']['ID'];
$this->username = $row['usr']['TUSERNAME'];
$this->firstname = $row['usr']['FIRST_NAME'];
$this->lastname = $row['usr']['LAST_NAME'];
$this->phone = $row['usr']['PHONE'];
$this->mobile = $row['usr']['MOBILE'];
$this->email = $row['usr']['EMAIL'];
$this->additional_info = $row['usr']['ADDITIONAL_INFO'];
$this->last_login_date = $row['usr']['LAST_LOGIN_DATE'];
$this->user_group = $row['usr']['USER_GROUP_ID'];
}
return true;
}
Am I doing it the right way, I'm not talking about the syntax, for now I focus on the class structure, design and best practices - any opinion would be appreciated.
Could I call the session_start(), for example, in the class constructor and use the vars inside it without calling it each time in a function !?
Should I close the DB connection via the close() function or is $conn=null acceptable !?
Is it a bad practice to store the database information in the session class !? If yes, where to store it as a 'global' variable - $_GLOBAL !?
If there is a 'PHP bes practice class structures in 5 minutes for dummies' please notify me :)
Thanks in advance.
Use define to define all of your constants.
For example:
define('DBCONNINFO', "something");
Also you only have to call session_start() once, it can be done anywhere in your script.
It doesn't make a lot of sense to fetch the data from the database for every request if you're using sessions anyway. In which case, why is session_start() being called inside the setUser() method?
And we can't really comment on the class structure when you've only provided a single method.
Also, since the representation of data leaving PHP should be appropriate to the substrate where that data is going (to prevent SQL injection, email header injection, CSS....) then it's good practice to defer changes to the representation of the data until just before the point where it leaves PHP. e.g.
$sql = "SELECT
....
WHERE usr.id = " . mysql_real_escape_string($id);
(or use bound parameters)
However since users are usually identify themselves by their username rather than their userid, it rather implies that $id came from somewhere other than user supplied data - in which case where? And why are you using this as the identifier when you've already got an identifier for the session (which is where this data should be getting stored).
Or do you want to use this class for processing data relating to users other than the user of the current session - in which case there is no way that there should be a session_start() in there.
Sorry - but this is not well thought out code and not a well presented question.
BTW, setting the connection to null does not close the database connection.

PHP: how would I use this simple class?

I was looking around for more "correct" login/logout portions of code, and found this one:
http://snipplr.com/view/1079/auth/
I got two questions though that stop me from using it.
1: How would I instantiate the class, and use it in my script?(I know PHP but am just befuddled for some reason)
2: there's the following lines:
global $db;
$db->query("sql here...");
How on earth does that make a database object? I think maybe I should create an object like $db = mysql_connect(...) outside the script, and global is calling it from outside the class?
If I know how to call this class, others will seem like a breeze, this is really helpful to me!
That code is dangerous, you should not use it in it's current state.
It blindly trusts $_COOKIE and creates SQL queries using string concatenation, without properly escaping input. Malicious users can easily perform SQL injection on any application using that class.
The presence of the var keyword, the presence of a constructor using the same name as the class and the lack of access control keywords in front of the methods tells me that the code was written for PHP4, not PHP5. It will still run, though
Both of these are fixable problems. First, let's address your questions.
The code written by #Delan Azabani is a good example of how to use the class.
The code is confusing. At first, it looks like the code is using a real database object instead of the old, low-level functions provided by the mysql extension. But then it goes and calls functions from the mysql extension! It's probably someone's custom-written wrapper. The code isn't actually creating a database object, it's simply referencing the value of $db in the global scope, as you suspect.
You've mentioned that you're using the mysql extension. I urge you to reconsider and use PDO or mysqli instead. Not only will this class work with either (though with some changes to mitigate the glaring security hole), but your own code will be better off using the more modern, safer techniques used in PDO and mysqli.
Let's fix the login method, using PDO.
public function login($username, $password) {
global $db;
$sth = $db->prepare("SELECT user_id FROM users WHERE username = ? AND password = ?");
$sth->execute(array($username, $password));
if($sth->rowCount() == 1) {
$this->user_id = $sth->fetchColumn();
...
Let's go over what changed. First, we added query placeholders, those are the question marks. The prepare method returns a statement handle, which you're already probably familiar with. Next, we tell the prepared statement to run itself using the execute method, passing an array of variables. The variables will be automatically escaped for you and then inserted into the query in place of the placeholders.
After the query has run, we use rowCount to pull back the number of matching rows. We want exactly one. Because we're pulling back the first column of the first row, we then use fetchColumn to grab just that bit of data.
The rest of the login method is just fine.
The check method needs similar fixing up.
public function check($username, $password) {
global $db;
$sth = $db->prepare("SELECT user_id, password FROM users WHERE username = ?");
$sth->execute(array($username));
if($sth->rowCount() == 1) {
list($db_user_id, $db_password) = $sth->fetch(PDO::FETCH_NUM);
if(md5($db_password . $this->salt) == $password) {
$this->user_id = $db_user_id;
...
Once again, we prepare a query with placeholders, then execute with the actual variables. Again we want only one row, but this time we want everything in the row. We'll use PDO::FETCH_NUM to tell fetch that we want a numerically indexed array, then we'll take the two resulting entries in the array and stuff them in $db_user_id and $db_password, using them where the old code called mysql_result. PDO doesn't let you pick and choose different columns from the same row using fetchColumn.
If you wanted to use the mysqli extension instead, there's a bit more work to be done. I hope I've convinced you to use PDO instead, though!
The rest of the class is, eh, adequate. Make sure to adjust the $domain class variable at the top to match your actual domain name, it's used in the cookies.
global $db just allows the global database pointer $db to be accessed from inside the class method. You need to create the database by running mysql_connect and mysql_select_db. The entire class is in class Auth, so instantiate an Auth object before doing anything else (well, after connecting to the database, of course).
You can then call the methods inside your Auth object. For example, if a login form submits to login-post.php, you can have this code inside:
$m = new Auth();
if ($m -> login($_POST['u'], $_POST['p'])) {
header('Location: /');
exit;
} else {
header('Location: login?wrong=1');
exit;
}
Looks like the code you posted is just assuming you have a variable defined in your global scope called $db that looks like a wrapper class to the native PHP MySQL resource. So yes, you should create $db outside in the global scope (i.e. not inside a class), but it's expecting a custom class.
I did a little searching, and it looks like he's using THIS class: http://snipplr.com/view/27966/class-db/
It asks you to create an ini file called "crunksauce.ini" (I kid you not) in the same directory as the executing script, and contains configuration variables. The config file should like this:
database = <your database name>
host = <your db host>
user = <your db user>
pass = <your db password>
After creating the config file, you can create the db object like this:
$db = new Db();

Categories