Php create class function to retrieve data from table - php

I'm new learner in php OOP, I want to create a class function to get register users info, how can I do that?
class Functions{
public static function getUserInfo($user_id){
$sql = mysql_query("SELECT * FROM members WHERE user_id='".$user_id."'");
$rows = mysql_fetch_array($sql);
if(mysql_num_rows($sql) >= 1){
return $rows;
}
}
}
to echo user's info:
$user = new Functions();
$user->getUserInfo($_SESSION['user_id']);
echo $user->user_email;
I got nuthing output with 'undefined property' message, what is the proper way to create function to retrieve user's info? thanks.

Maybe that?
class Functions{
public static function getUserInfo($user_id){
if(empty($user_id)) {
return null;
}
// connect to db
$sql = mysql_query("SELECT * FROM members WHERE user_id='".$user_id."' LIMIT 1");
if(mysql_num_rows($sql) > 0){
$row = mysql_fetch_array($sql, MYSQL_ASSOC);
// close connection to db
return $row;
}
// close connection to db
return null;
}
}
$userID = !empty($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
$user = Functions::getUserInfo($userID);
if($user !== null) {
echo $user['user_email'];
}
This is ony example, use mysqli_* or PDO to manage data in database.

mysql_fetch_array returns array, not object.
$user['user_email'] should work.
In general as you mentioned OOP I would say your code is using classes, but it is not OOP (if I understand correctly how you're going to structure it). What you do is simply wrapping procedural code into a class.
With OOP you need to structure code such a way that it has self-contained objects, so creating "Functions" class containing various utility methods is generally a bad idea. Consider e.g. creating User object instead.
For database abstraction I would recommend checking PDO (http://www.php.net/manual/en/class.pdo.php).

Related

PHPUnit 4.8 Mock mysql database interface

Good afternoon,
I have a bunch of legacy code that uses the old mysql library (mysql_query($sql) for example) and am trying to test it with PHPUnit (4.8 is the latest that will run on the server for various reasons).
Does anyone know how to mock this database connection so that it can return predetermined results when predetermined queries are run? I have tried using getConnection() (as per the docs here: http://devdocs.io/phpunit~4/database) to no avail.
For example I have this class:
class Raffle {
...
public static function loadAll($filter=""){
//$filter = mysql_real_escape_string($filter); // protect against SQL injection
$raffles = []; // the array to return
$sql = "SELECT * FROM raffles $filter;"; // include the user filter in the query
$query = mysql_query($sql);
//echo mysql_error();
while($row = mysql_fetch_assoc($query)){
$raffles[] = Raffle::loadFromRow($row); // generate the raffe instance and add it to the array
}
return $raffles; // return the array
}
...
}
(The mysql_connect() call is done in a file called db.php which is loaded on every page that it is needed and not in the class file itself.)
Thanks in advance.
For anyone else stuck in this situation I found that building a mock for PDO that contains a fallback to the functional api allowed me to migrate the code to a Testable OO based model while still using the old mysql library under the hood.
For example:
// the basic interfaces (function names taken from PDO
interface DBConnAdapter {
public function query($sql);
}
// since PDO splits connections and statements the adapter should do the same
interface DBQueryAdapter {
public function num_rows();
public function fetch_assoc();
}
...
class DBAdapter implements DBConnAdapter {
public function query($sql){
$query = mysql_query($sql); // run the query using the legacy api
return $query ? new QueryAdapter($query) : false; // return a new query adapter or false.
}
}
...
// an example of a basic mock object to test sql queries being sent to the server (inspired by mockjax :-) )
class DBMock implements DBConnAdapter {
public $queries = []; // array of queries already executed
public $results = []; // array of precomputed results. (key is SQL and value is the returned result (nested array))
public function query($sql) {
if($this->results[$sql]){
$query = new DBQueryMock($sql, $this->results[$sql]); // a mock of PDOStatement that takes the sql it ran and the results to return
$queries[] = $query; // add the query to the array
return $query; // return the query
}
return false; // we do not know the statement so lets pretend it failed
}
// add a result to the list
public function add_single_result($sql, $result){
// check if the index was set, if not make an array there
if(!isset($this->results[$sql])) $this->results[$sql] = [];
// add the result to the end of the array
$this->results[$sql][] = $result;
// return its index
return count($this->results[$sql]) - 1;
}
}
Admittedly this is not an ideal solution as it requires modifying the code to support the adapter objects and removes some functionality (such as mysql_real_escape_string), but it worked....
If you have a better solution please share :-) Thanks!

PHP and PDO class

I am trying to learn OOP and decided to make a class which uses PDO.Here some codes from my class.
class DB extends PDO {
public function _construct($dsn,$user,$pass,$options=""){
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
try {
parent::__construct($dsn, $user,$pass,$options);
$this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function run($query,$all="",$secure=""){
if(empty($secure)){
$qry=$this->query($query);
}else{
$qry=$this->prepare($query);
$qry->execute($this->cleanup($secure));
}
if($all=="all"){
return $qry->fetchAll(PDO::FETCH_ASSOC);
}else{
return $qry->fetch(PDO::FETCH_ASSOC);
}
}
private function cleanup($secure) {
if(!is_array($secure)) {
if(!empty($secure))
$secure = array($secure);
else
$secure = array();
}
return $secure;
}
public function rowCount($table,$extra=""){
$query="Select count(*) from ".$table;
if(!empty($extra)){
$query="Select count(*) from ".$table." ".$extra;
}
$qry=$this->query($query)->fetchColumn();
return $qry;
}
public function select($table,$extra=""){
$query="Select * from ".$table;
if(!empty($extra)){
$query="Select * from ".$table." ".$extra;
}
return $this->query($query);
}
}
What is difference between following codes why i don't get the same result ?
//usage 1 (it doesnt work that way)
$return =$qry->fetchAll(PDO::FETCH_ASSOC);
return $return;
//usage 2 (it is exactly what i need but i want to learn the difference)
return $qry->fetchAll(PDO::FETCH_ASSOC);
Edit : I realy don't know what I was doing wrong but it seems there is no difference between these usages.They both work now.
This is how I use my method
$result=$db->run("my query","all");
foreach($result as $r){
//
}
In the construct method i use PDO's query method to set character to utf-8 but it does not work. If I use after created a DB object it works.
try {
parent::__construct($dsn, $user,$pass,$options);
$this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->query("SET NAMES 'UTF8'");
$this->query("SET CHARACTER SET UTF8");
}
last question
//what do u think about this usage.I didnt run accross some thing like this
//all the pdo classes i checked use it just
// return $qry->fetchAll(PDO::FETCH_ASSOC);
//do you think i need to separate "fetchAll" and "fetch"
if($all=="all"){
return $qry->fetchAll(PDO::FETCH_ASSOC);
}else{
return $qry->fetch(PDO::FETCH_ASSOC);
}
Don't extend PDO it's just wrong in so many ways. You should instead use it like your title suggests
class Database
{
protected $pdoInstance;
public function __construct($pdoInstance)
{
$this->pdoInstance = $pdoInstance;
}
public function query($query)
{
$preparedStatement = $this->pdoInstance->prepare();
/* bla bla bla */
}
}
This code makes a lot more sense, and is a much better example of good object oriented programming. (It still makes me cringe however, but it's a good start)
First of all, such a good questions can be rarely seen here.
Very few people understand the need of an abstraction class upon PDO.
So, here are some suggestions.
Don't make run into single function. it is much more convenient to have separate methods for different result types. Compare
$data = $db->getAll($sql);
$data = $db->run($sql,"all");
$data = $db->getOne($sql);
$data = $db->run($sql,"one");
$data = $db->getCol($sql);
$data = $db->run($sql,"col");
You need to think of the function names. Your "cleanup" function doesn't do any cleanup.
I would use func_get_args() instead.
What is difference between following codes why i don't get the same result ?
There is no difference
$return = $qry->fetchAll(PDO::FETCH_ASSOC);
return $return;
should work. Define "it doesnt work".
In the construct method i use PDO's query method to set character to utf-8 but it does not work.
Although you should set charset in DSN, this one should be working too. Define "not working"
Also I would suggest to create DSN in the constructor, making config file more familiar.
You may wish also to get some ideas from my mysql helper class. Though it is using different approach from prepared statements, it is way more secure than PDO

What is correct syntax for calling a function recursively in php

I have a function which is using recursion to call itself and I need to know the correct syntax for calling itself.
Note: I am using Object oriented programming technique and the function is coming from a class file.
Below is my function
// Generate Unique Activation Code
//*********************************************************************************
public function generateUniqueActivationCode()
{
$mysql = new Mysql();
$string = new String();
$activation_code = $string->generateActivationCode();
// Is Activation Code Unique Check
$sql = "SELECT activation_id FROM ". TABLE_ACTIVATION_CODES ." WHERE activation_code='$activation_code' LIMIT 1";
$query = $mysql->query($sql);
if($mysql->rowCount($query) > 0)
{
// This function is calling itself recursively
return generateUniqueActivationCode(); // <- Is this syntax correct in Oops
}
else
{
return $activation_code;
}
}
Should the code to call it recursively be
return generateUniqueActivationCode();
OR
return $this->generateUniqueActivationCode();
or if something else other than these 2 ways.
Please let me know.
You would need to call it with the $this variable since your function is part of the instance. So:
return $this->generateUniqueActivationCode();
PS: Why not just try both methods and see if it generates any errors?
Recursion is the COMPLETELY WRONG WAY TO SOLVE THIS PROBLEM
Unlike iteration you're filling up the stack, and generating new objects needlessly.
The right way to solve the problem is to generate a random value within a scope which makes duplicates very unlikely, however without some external quantifier (such as a username) to define the scope then iteration is the way to go.
There are further issues with your code - really you should be adding records in the same place where you check for records.
I am using Object oriented programming technique and the function is coming from a class file
Then it's not a function, it's a method.
And your code is susceptibale to SQL injection.
A better solution would be:
class xxxx {
....
public function generateUniqueActivationCode($id)
{
if (!$this->mysql) $this->mysql = new Mysql();
if (!$this->string) $this->string = new String();
$limit=10;
do {
$activation_code = $string->generateActivationCode();
$ins=mysql_escape_string($activation_code);
$sql="INSERT INTO ". TABLE_ACTIVATION_CODES ." (activation_id, activation_code)"
. "VALUES ($id, '$ins)";
$query = $mysql->query($sql);
if (stristr($query->error(), 'duplicate')) {
continue;
}
return $query->error() ? false : $activation_code;
} while (limit--);
return false;
}
} // end class

Using config variables inside functions

In the code given below, I am trying to modify it in such a way that the db connection variables are used from a config file. This should make the password more secure as I can restrict the config file's permissions.
Kindly let me know if there is a way by which I can modify the code to get the db variables from another file/config file?
class ActivitycodesCollection {
var $list, $err, $sql;
// --- Private variables for database access
var $_db_host = "######";
var $_db_username = "######";
var $_db_passwd = "######";
var $_db_name = "######";
function query ($where="") {
mysql_pconnect ($this->_db_host, $this->_db_username, $this->_db_passwd);
mysql_select_db ($this->_db_name);
$where = "WHERE " . $where;
$sql = "SELECT * FROM activitycodes $where";
$result = mysql_query ($sql);
$this->err = mysql_error();
$this->sql = $sql;
if (mysql_num_rows($result) > 0) {
while (list($id) = mysql_fetch_array ($result)) {
$this->list[$id] = new activitycodes($id);
}
}
}
}
I tried including the config.ini file in this class/function but it threw an error like
unexpected T_VARIABLE, expecting T_FUNCTION
Your code is hopelessly outdated.
1) Don't use var for properties, use private or protected.
2) Don't use mysql_* functions, use PDO.
3) Don't keep connection details inside the class. Just require PDO connection in constructor.
4) Don't trust any data outside your scope - don't allow just write some untrusted text into your SQL query (you do it by $where variable).
5) Read books. "PHP Objects, Patterns, and Practice" will help you now, and "Clean code" - little bit later.
Example:
class ActivitycodesCollection
{
private $list;
private $PDO;
private $table_name;
public function __construct(\PDO $PDO, $table_name)
{
$this->PDO = $PDO;
$this->table_name = $table_name;
}
public function fetchByParameter($parameter)
{
$query = $this->PDO->prepare("SELECT `id` FROM `{$this->table_name}` WHERE "
." some_field = :parameter");
if (!$query)
{
return false;
}
if (!($query->execute(array(':parameter'=> $parameter))))
{
return false;
}
$results = $query->fetchAll(\PDO::FETCH_ASSOC);
if (!empty($result))
{
foreach ($results as $result)
{
$id = $result['id'];
$this->list[$id] = new ActivityCodes($id);
}
}
}
}
Without seeing the "config" file it's not possible to say how to write a parser for it. A simple solution would be to write some php code which sets the variables - but if you include / require it, the variables will be set in global scope - not within the method. But you could eval(file_get_contents($config_file_path)) - which would set the variables in local scope at the risk of providing a method for code injection.
BTW there are a large number of issues with the code you have provided. Leaving aside the potential risk of SQL injection, if the method parameter is null / blank, then the query will be malformed (consider function query ($where="1"). Relying on specific column ordering is bad practice.
It's also hard to imagine how yo restrict access to this config file when the only practical means would be via suphp or base opendir.
Putting the SQL connection data in a separate files does not increase security at all. Actually, storing them in a file that does not have a .php extension makes it less secure since it might be accessible by a user while the code of a PHP file is not visible to any users. You also cannot use more restrictive permissions on the config file than on your PHP files since whatever user PHP is running as (usually the webserver user) needs to access them.
Simply store the connection data in a PHP file:
<?php
define('DB_HOST', '...');
define('DB_NAME', '...');
define('DB_USER', '...');
define('DB_PASS', '...');
Then include this file (outside your class definition) and use the constants when making the connection.
You can use parse_ini_file in you constructor.
class ActivitycodesCollection {
var $list, $err, $sql;
const CONFIG_FILE = 'config.ini';
// --- Private variables for database access
var $_db_host = ''
var $_db_username = '';
var $_db_passwd = '';
var $_db_name = '';
public function ActivitycodesCollection() {
$config = parse_ini_file(self::CONFIG_FILE);
$this->_db_host = $config['db']['host'];
//etc
}
public function query ($where="") {
mysql_pconnect ($this->_db_host, $this->_db_username, $this->_db_passwd);
mysql_select_db ($this->_db_name);
$where = "WHERE " . $where;
$sql = "SELECT * FROM activitycodes $where";
$result = mysql_query ($sql);
$this->err = mysql_error();
$this->sql = $sql;
if (mysql_num_rows($result) > 0) {
while (list($id) = mysql_fetch_array ($result)) {
$this->list[$id] = new activitycodes($id);
}
}
}
And the ini file should be something like that :
[db]
host = localhost
name = foo
user = bar
pass = baz

PHP/MySQL performance question

Just had a quick question for those of you knowledgeable about performance. I have created a "MySQL" class, and every time I perform a query, I create a new MySQL object. See below
public function get_am_sales() {
$mysql = new MySQL();
$mysql->connect();
$query = "some query";
$mysql->query($query);
$result = $mysql->return_assoc();
unset($mysql);
return $result;
}
public function get_pm_sales() {
$mysql = new MySQL();
$mysql->connect();
$query = "some query";
$mysql->query($query);
$result = $mysql->return_assoc();
unset($mysql);
return $result;
}
public function get_comp_sales() {
$mysql = new MySQL();
$mysql->connect();
$query = "some query";
$mysql->query($query);
$result = $mysql->return_assoc();
unset($mysql);
return $result;
}
$sales = new Sales();
$amSales = $sales->get_am_sales();
$pmSales = $sales->get_pm_sales();
$compSales = $sales->get_comp_sales();
The code above obviously works, but I was wondering if this is a performance hit since I open and close a connection with every function call. I have tried to implement the class using one connection, but I get errors. See below
public function connect() {
$this->mysql = new MySQL();
$this->mysql->connect();
}
public function get_am_sales() {
$query = "SELECT site_id, dly_sls AS am_sales, cov_cnt AS am_covers
FROM v_sales_yesterday
WHERE am_pm = 'AM'
GROUP BY site_id
ORDER BY site_id ASC";
$this->mysql->query($query);
$result = $this->mysql->return_assoc();
return $result;
}
public function get_pm_sales() {
$query = "SELECT site_id, dly_sls AS pm_sales, cov_cnt AS pm_covers
FROM v_sales_today
WHERE am_pm = 'PM'
GROUP BY site_id
ORDER BY site_id ASC";
$this->mysql->query($query);
$result = $this->mysql->return_assoc();
return $result;
}
public function get_comp_sales() {
$query = "SELECT business_date, site_id, dly_sls AS comp_sales
FROM v_sales_today_comp
WHERE am_pm = 'PM'
GROUP BY site_id
ORDER BY site_id ASC";
$this->mysql->query($query);
$result = $this->mysql->return_assoc();
return $result;
}
public function disconnect() {
unset($this->mysql);
}
$sales = new Sales();
$sales->connect();
$amSales = $sales->get_am_sales();
$pmSales = $sales->get_pm_sales();
$compSales = $sales->get_comp_sales();
$sales->disconnect();
Does the mysql connection close after the "connect" function executes? If deemed necessary, what would be the best way to keep the connection open (using an object oriented approach)? Please let me know if you need anymore details, and I appreciate the help in advance.
This is like totally unnecessary. You dont have to open and close connections for each query. Are you using some kind of a framework? If not you must as all frameworks have active records and DB helpers to make interacting with DB easier. THis would be a great article for you
http://net.tutsplus.com/tutorials/php/real-world-oop-with-php-and-mysql/
has just what youre lookng for.
In general, you only want to create your MySQL instance once during the execution of the application.
If you have an overarching Application object then you could just create your MySQL instance inside of the Application object and access it from there.
The other alternative is to create a Singleton object for your MySQL instance that is then accessed via an 'instance()' method.
This way you only open a single connection during the execution cycle of your php script and it will be discarded at the end of script execution.
So now your code looks like so:
$query = "SELECT * FROM users";
$rs = Mysql::instance()->query($query);
If you need working examples of how to setup a Singleton instance for your purposes you can look at:
GacelaPHP
Kohana Database Class
Zend DB Adapter

Categories