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.
Related
I am currently working on a CMS and am learning how to use OOP.
My question is: How do I take variables set in a mysql database and use them on my website?
Lets say I have 2 columns, one called var_name and var_content.
How would I use it so that $var->sitetitle; echos out whatever it matches up to in my database?
I don't know what this is called, if anyone could lead me in the right direction, I appreciate it!
Right now, I have this:
require_once("classes/database.class.php");
$database = new database();
$database->set_value('sitevariables', $database_prefix . "sitevariables");
$database->set_value('host', $database_host);
$database->set_value('pass', $database_pass);
$database->set_value('user', $database_user);
$database->set_value('table', $database_table);
I wanted it so I could use $database->host to get my mysqli server. It's basically the same thing as I want to do, except it takes from the database to get and set the values
you can define a function to get variables, once your database connection is set up (I sadly not think it is possible to query the database for credentials to connect to that vary database. kind of spiraling thing there.)
this takes into account that var() is a member function of your database() class. Since I don't have your database class, I don't think the way I'll query the database is like yours, but you will be able to fix that.
function var($var_name) {
$stmt = $this->query('SELECT var_content FROM variables WHERE var_name=?');
$stmt->execute(array($var_name));
return $stmt->fetch(PDO::FETCH_COLUMN);
}
$sitetitle = $database->var('sitetitle');
I'm mostly a designer and don't have a lot of experience with OOP in PHP, so please be kind as my terminology may not be exactly precise. It's the PHP/OOP syntax that I need the most help with, and I've searched for a solution several times here and on Google as I imagined this would be a pretty straight forward question but haven't found anything to help.
I'm trying to create a class method that pulls client account data from a database using the client's account ID. There are about 20 variables I want to pull and have access to on various pages on my site.
Here's my class file (classfile.php):
class Accounts{
// Function to get client data from database.
public function getAccount($acctId){
require("/var/www/vhosts/aqios.com/httpdocs/00omvat/dbinfo.php");
mysql_connect("localhost","user","password") or die();
mysql_select_db("database") or die();
$query = "SELECT * FROM clients WHERE id='$acctId' LIMIT 1";
$result = mysql_query($query) or die();
while($row = mysql_fetch_array($result)){
$this->$firstName = $row["firstName"];
$this->$lastName = $row["lastName"];
$this->$address1 = $row["address1"];
$this->$address2 = $row["address2"];
$this->$city = $row["city"];
$this->$state = $row["state"];
//etc., etc.
}
mysql_close();
}
}
Here's one of my pages (index.php):
include_once('classfile.php');
$acctId = 111111;
$object = new Accounts();
$object->getAccount($acctId); //Script dies unless I comment this line out.
First of all, the script dies unless I comment out that last line, so something must be wrong with my syntax there. But what I really need to know is how to call and place the city or any other of these variables into my page? I don't know the proper syntax. I can't imagine it would be $object->getAccount($acctId)->$city. I know that's wrong. How would I call the city or any other variable from this object?
Also, I do know that I should be using another method to connect to my database, and I will do that once I get this figured out first.
Thank you in advance for any help you can offer!
Jason
This is incorrect
$this->$firstName = $row["firstName"];
^---remove the $
It should be
$this->firstName = $row['firstName'];
And the same for the subsequent lines.
As mentioned by others, you should use $this->firstName instead of $this->$firstName
$this refers to the object, not to the method
It will work without explicit initialization, but you should define for better reading all your object fields as public (or private/protected and write getter methods):
class Accounts {
public $firstName;
public $lastName
...
}
With variables defined as in 3, you should be able to refer to their values with $object->firstName
You should probably consider splitting classes into two - Accounts (as a DB proxy) and Account (as a single account data) and in Accounts->getAccount you will create Account object and return it - but this is more of a architectual discussion
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.
}
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();
In PHP I know many people will use a class to SET and GET session variables, I am doing this now in many classes, I need to know if I am doing it wrong though.
So for example lets pretend I have A class that need to use this
$session->get('user_id')
Which gets this value
$_SESSION['user_id']
Now in this class if I have 15 methods and in each method I need to access this value several time, currently I am calling $session->get('user_id') 20 times in a class if it is needed 20 times, should I be setting this 1 time per class to a local variable for that class and then access it? I am not sure if it makes any difference or not, my theory is that the way I am doing it now is 20 extra function calls that could be avoided?
If my theory is correct, what would be the best way to store these values inside a class? Like a private or public or protected variable?
Thanks, sorry for any confusio, classes and objects are taking me a while to learn.
Also note that $session->get('user_id') is just 1 of many DIFFERENT variables I would need to do the same thing to as well.
UPDATE
After reading Chacha102's post about using an array() ... here is what I have tried, does this look like a good way or still can be improved a lot?
class file
<?PHP
class User
{
// Load user details into an Array
public function load_user()
{
$this->user_id = $this->session->get('user_id');
//if user ID is already set, then Load the cached urser data
if(isset($this->user_id) && $this->user_id != ''){
// set user data to an array
$this->user['user_id'] = $this->user_id;
$this->user['user_name'] = $this->session->get('user_name');
$this->user['pic_small'] = $this->session->get('pic_small');
$this->user['sex'] = $this->session->get('sex');
$this->user['user_role'] = $this->session->get('user_role');
$this->user['location_lat'] = $this->session->get('location_lat');
$this->user['location_long'] = $this->session->get('location_long');
$this->user['new_user'] = $this->session->get('new_user');
return $this->user;
}
}
}
?>
main page file
<?PHP
require 'user.class.php';
$user = new User;
// if a user_id is set into a session variable then we return an array of other user related data
$user->account = $user->load_user();
// would show the user's ID from our array
echo $user->account['user_id'];
?>
If you are doing something like this:
if($session->get('user_id')==1)
{
$prefs = get_prefs($session->get('user_id'));
$info = get_info($session->get('user_id'));
}
then I would replace it with a since local variable
$id = $session->get('user_id');
if($id == 1)
{
//.....
}
It increases clarity for one. It probably isn't a big deal to call a simple function like that over and over again, but I still wouldn't do it.
I try to reduce the number of functions I call in a single method. If you are doing something like:
$user_id = $session->get('user_id');
$name = $session->get('name');
// ... etc ...
You might just want to grab an array of all the session variables instead.
$user = $session->get_array();
echo $user['user_id'];
This reduces the function calls, and you get all the data in one fell swoop.
Just one thing on clarity, using an array of user data is probably easier to read than to create a variable for each thing ($user_name, $user_id, etc).
For accesses distributed over a number of methods, as long as you're just using the function to access the variable, I'd say stay with the function. The additional cost is minuscule, and it's better for long term maintainability.
Within the same method, you would make one function call, populating a local variable, as Chacha102 suggests.
Even if the function does resource-intensive things like database calls, I would prefer giving the function some internal caching before adding a member to your class.
Adding the variable as a member to your class doesn't really make sense in the OOP way, because it's not a logical, legitimate member of the class but just a temporary variable.