I'm working on a Content Management System for My wife who wants to create a website, and I have a way I've always done things within the past, but I want to deliver better coding procedures, so this is my dilemma.
This is Code I've used in the past that I know works.
class accounts {
public function CheckAccountLogin() {
global $db;
$query = <<<SQL
SELECT id,gaToken
FROM accounts
WHERE password_hash = :hashedpw
SQL;
$resource = $db->sitedb->prepare( $query );
try {
$resource->execute( array (
':hashedpw' => sha1($_POST['user-name'].':'.$_POST['user-pass']),
));
if($resource->rowCount() == 0 ) { echo false;}
else {
foreach($resource as $row) {
$this->authkey = $row['gaToken'];
if($this->authkey == "") {
self::SetSession();
}
else {
self::CheckAuth();
}
}
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
}
Now every function would need global $db at the start of the function in order to utilize $db->sitedb or else we would have an error thrown our way, so what I want to do instead is
class accounts {
public $db = new db();
public function CheckAccountLogin() {
$query = <<<SQL
SELECT id,gaToken
FROM accounts
WHERE password_hash = :hashedpw
SQL;
$resource = $this->sitedb->prepare( $query );
try {
$resource->execute( array (
':hashedpw' => sha1($_POST['user-name'].':'.$_POST['user-pass']),
));
if($resource->rowCount() == 0 ) { echo false;}
else {
foreach($resource as $row) {
$this->authkey = $row['gaToken'];
if($this->authkey == "") {
self::SetSession();
}
else {
self::CheckAuth();
}
}
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
}
This way within all my new functions I'm able to simply declare $this->sitedb whenever I need to connect to the database. With the above code I'm given
Parse error: syntax error, unexpected 'new' (T_NEW) in /var/www/html/functions.d/accounts.class.php on line 3. I know where the issue is, I'm just looking for a cleaner way than my first code block. Any help in getting this to work correctly would be greatly appreciated.
You can't initialize a variable there unless it can be evaluated at compile time. So you can't call new there. See the docs. Do it in the constructor.
class accounts {
public $db;
public function __construct() {
$this->db = new db();
}
}
You can create a global class DbConnect where you statically define the database object db and connect it to your database, in this way you will keep a single database connection object throughout your application.
Include this class at the beginning before any code, then you can access this object anywhere through :: operator in any class that follows.
Related
I'm interested in use the Database class described in http://php.net/manual/en/pdo.begintransaction.php
But that class has a problem, it uses a $transactionCount attribute that is not static, that means that if I have multiple classes beginning transactions it will cause multiple commits and will make my code finally go wrong, look this example (not runnable, simply for understand):
class Field extends Database {
public function createFieldToForm( $fieldName, $formId )
{
// static transactionCount = 0
// transactionCount = 0
$this->beginTransaction();
// .... createFieldToForm code ....
$last_id_new_fieldName = $this->insert( $fieldName );
$formFields = new FormFields();
$formFields->assignFieldToForm( $last_id_new_fieldName, $formId );
$this->commit();
}
public function insert( $fieldName )
{
try {
// static transactionCount = 1
// transactionCount = 1
$this->beginTransaction();
$dbh = Database::getDatabaseConnection();
$dbh->prepare( "INSERT INTO form(fieldname) VALUES (:fieldname)" );
// ... bind ...
$dbh->execute();
$this->commit();
return $dbh->lastInsertId();
}
catch (PDOException $e) {
$this->rollback();
}
}
}
class FormFields extends Database {
public function assignFieldToForm( $idFieldName, $formId )
{
// static transactionCount = 1
// transactionCount = 0
$this->beginTransaction();
// ... assign the created field to the form ....
$this->insert( $idFieldName, $formId );
$this->commit();
}
public function insert( $idFieldName, $formId )
{
try {
// static transactionCount = 2
// transactionCount = 1
$this->beginTransaction();
$dbh = Database::getDatabaseConnection();
$dbh->prepare( "INSERT INTO form_fields(idfield,formid) VALUES (:idfield,:formid)" );
// ... bind ...
$dbh->execute();
$this->commit();
}
catch (PDOException $e) {
$this->rollback();
}
}
}
const FORM_USER_INFORMATION = 3;
$fieldPhone = new Field();
$fieldPhone->createFieldToForm( "phone_number", FORM_USER_INFORMATION );
As you can see in the comments of this code the values of the $transactionCount is very different if it's static or not, but the main point of this question is about the static attribute, if is possible that its value could be changed by another code threads/functions or outside callings during the execution of (for example) createFieldToForm. What you can recommend to me to go ahead?
This class is not from the PHP manual but from the comments to the manual page. Which makes it deliberately unreliable source.
To solve your problem just get rid of all these "transactions". As it makes no sense to use a transaction for just a single query.
Therefore, most likely you don't need neither transactions, not counters, nor this class at all.
I'm trying to call parent class constructor but it throws an error
Fatal error: Cannot call constructor
and the same code was working well before, I didn't change anything and but suddenly don't know what could have happened, It is throwing this error.
I've read some answers on stackoverflow, but they say that your parent class doesn't contain a constructor, well, this is not my case I have constructor in my parent class. Here's my code:
class DB
{
var $con;
public function __construct()
{
require_once 'configs/dbconfig.php';
$this->connect();
}
function connect()
{
try{
$this->con = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
$this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}catch(PDOException $ex) {
echo $ex->getMessage();
}
}
}
and then I have a class Posts which is extending DB and calling DB's constructor.
class Posts extends DB
{
var $user_id;
public function __construct($user_id)
{
parent::__construct();
$this->user_id = $user_id;
}
function get_posts($search,$pages,$since_id=0,$max_id=false,$count=20,$status='active')
{
$extra = '';
if($search) $extra .= " AND text LIKE CONCAT('%',:search,'%')";
if(!empty($pages)) $extra .= " AND page IN('".implode("','", $pages)."')";
if(!empty($status) && $status != 'all') $extra .= " AND status=:status";
$max_id = ($max_id) ? $max_id : time();
$sqlCommand = "SELECT id,pid,text,media,media_url,type,name,u_id,username,user_profile_url,user_photo_url,post_url,date,status,source,page_id FROM ".POSTS." WHERE date>=:since_id AND date<=:max_id".$extra." AND user_id=:user_id ORDER BY date DESC LIMIT $count";
$params = array(':since_id'=>$since_id,':max_id'=>$max_id,':user_id'=>$this->user_id);
if($search) $params[':search'] = $search;
if($status && $status != 'all') $params[':status'] = $status;
$posts = $this->fetch($sqlCommand,$params);
return $posts;
}
}
This is with your php version, It must have been changed, please check the version of php and try to update that.
I think this is a known PHP bug (look here), try to make a function in DB that returns a new DB (by calling constructor) and in Posts call this function that you created.
Well maybe it's a basic silly answer, but did you try 'require'?
Im relatively new to programming, with about 1 years part-time learning experience, im very new to PHP, only about a few weeks and using w3schools to help me
Im now trying to make the switch to OOP style and just cant understand the concept, or rather how and when to apply it and have thus turned here, where I have been a long time lurker instead of contributor for some help and advice.
I would like some help / short explanation how I would write the folloing in a PHP oop way
$sql="SELECT name, lastname, member_nr, joindate, order, creditCardInfo
from members
WHERE member_nr = $'member_nr'";
$result = mysql_query($sql) or die("error");
while($row = mysql_fetch_array){
echo '<h3>Personal Profile</h3>';
echo $name = $row['name'];
echo $lastName = $row['lastname'];
:
:
}
My problem is I dont know if I should create a class for the above, personal profile can be seen as a person right which is an object...? But do I include the HTML part and the mysql_query part etc in my class...Ive just got so many questions when it comes to OOP, its very hard to learn on your own thats why im really appreciate any drop of help or advice I can get on here
Thank you
First you should use mysqli, as all mysql_* are deprecated and are removed from PHP in the future.
Here a basis class with some functions, but you should expand it for your use! And learn what the functions do which got no comments on your own, to learn more.
This makes multiple connections to the database, so reading some stuff about singleton would be good for you too!
<?php
class dbconnection {
private $dbHostname;
private $dbName;
private $dbUsername;
private $dbUserpassword;
private $error;
private $querysuccess;
private $connected;
private $mysqli;
public function __construct() {
$this->dbHostname = 'localhost';
$this->dbName = 'databasename';
$this->dbUsername = 'username';
$this->dbUserpassword = 'password';
$this->connected = false;
}
public function __destruct() {
$this->mysqli->Close();
}
public function connect() {
//establishing a database connection
$this->mysqli = new mysqli($this->dbHostname, $this->dbUsername, $this->dbUserpassword, $this->dbName);
if($this->mysqli->connect_errno) {//When there was an error during the connecting
echo 'Connection Error:<br>'.$this->mysqli->connect_error;
$this->connected = false;
} else {
$this->connected = true;
}
if(!$this->mysqli->set_charset('utf8')) {//Need to be done for some functions!
echo 'Error during seting the charset: <br>'.$this->mysqli->error;
}
}
public function doquery($query_str) {
//method which executes the query
$returnval = false;
if($this->connected && $query_str != '') {
//only when connected AND the query is not empty
$res = $this->mysqli->query($query_str);//this is the equivalent of mysql_query
if($this->error_get() == '') {//Check for an error
$this->querysuccess = true;
} else {
$this->querysuccess = false;
}
$returnval = $res;
} else {
echo 'No database connection, this needs some!';
}
return $returnval;
}
public function query_success() {
return $this->querysuccess;
}
public function affected_rows_get() {
return $this->mysqli->affected_rows;
}
public function error_get() {
return $this->mysqli->error;
}
public function insert_id_get() {
return $this->mysqli->insert_id;
}
public function escape_str($str) {
return $this->mysqli->real_escape_string($str);
}
public function is_connected() {
return $this->connected;
}
public function fetch_assoc(&$res){
return $res->fetch_assoc();
}
public function fetch_assoc_array(&$res){
return $res->fetch_array(MYSQLI_ASSOC);
}
}
This case wouldn't be a good example. You want a class when you want to encapsulate logic of one entity to simplify its use outside the class.
For example:
class Member {
private $id, $name,
$lastname, $member_nr, $joindate, $order, $creditCardInfo;
public function __construct($id = 0) {
if($id != null) $this->loadFromDB();
}
private function loadFromDB() {
//Do db load here...
}
public function Update(){
//Do db update
}
public function Delete() {
//Do db delete...
}
public function GetFromMemberNR($nr) {
//Do select
}
//Additional Functions Verfication
}
In the end you'll have fairly complex code here. But to use it outside you just include the class's php file.
include 'member.php';
$member = new Member();
$member->GetFromMemberNR(2); //Does everything for you inside the function..
There are plenty of tools to help you do database operations easier, but that is the basis of OOP. The main idea is Encapsulation for reusability.
i have problem in MYSQL select in OOP PHP. i do not know how to write it correct.
my code is:
$sql = "SELECT name_mcategory
FROM web_main_category WHERE userid=('".$userid."')";
$result = mysql_query($sql);
$e=0;
$maincat=array ();
while($data=mysql_fetch_array($result))
{
$maincat[$e]=$data['name_mcategory'];
$e++;
}
how to write it in the OOP? i have tried this but it was not working.
class nweb {
var $userid;
var $mcategory;
function Getmain_category () {
$rs = mysql_query("SELECT name_mcategory
FROM web_main_category WHERE userid=$this->userid");
}
$this->tab=mysql_fetch_object($rs);
}
}
in the print page
$mcat = new nweb();
$mcat->getmain_category ();
$mcat->mcategory=$this->name_mcategory;
how to get data like a $maincat[$e]=$data['name_mcategory'];
If you want to use OOP, then use an OOP DB Layer like PDO:
class nweb extends PDO {
public $userid, $mcategory;
public function __construct($hostname, $dbname, $username, $password) {
parent::__construct($hostname,$dbname,$username,$password);
}
public function getmain_category() {
return $this->query("SELECT name_mcategory FROM web_main_category WHERE userid = {$this->userid}")->fetch();
}
}
$mcat = new nweb('hostname', 'dbname', 'username', 'password');
var_dump($mcat->getmain_category());
Note: You add some error handing, see pdo::query.
In OOP we usually make a separate class to handle the database operation . For example Database.php
so it executes the query and return the result to Category.php or make Category inherit Database.php.
If you want a better way use the PHP Activerecord.
check like this
class nweb {
var $userid;
var $mcategory;
function getmain_category () {
$rs = mysql_query("SELECT name_mcategory
FROM web_main_category WHERE userid = {$this->userid}");
return mysql_fetch_object($rs);
}
}
//print page
$mcat = new nweb();
$data = $mcat->getmain_category ();
$e=0;
$maincat=array ();
while($data=mysql_fetch_array($result))
{
$maincat[$e]=$data['name_mcategory'];
$e++;
}
I am developing a project in which two portions of webpage frequently change and fetch recent data. I have some confusion about whether to use mysql_connect or mysql_pconnect? I have one config file that is being included in every page. There is one database connection object which I use for queries. Even when approximately 70 users are online it shows 20,000 connections on my server. Please suggest me the best way to keep a single connection alive from a single user, so there should be 70 connections when there are 70 users online. Currently I'm not using mysql_close method to close connection. Is this the reason it shows these many connections? Your advice will really be appreciated.
A common pattern used in this case is the singleton pattern, here's some rough code.
class DB_Instance
{
private static $db;
public static function getDB()
{
if (!self::$db)
self::$db = new Database();
return self::$db;
}
}
function getSomething()
{
$conn = DB_Instance::getDB();
.
.
.
}
Some examples/references
http://tutorialpedia.org/tutorials/Singleton+pattern+in+PHP.html
http://www.ricocheting.com/static/code/php/mysql-v3/Database.singleton.phps
http://netlinxinc.com/netlinx-blog/53-php/7-applying-the-singleton-pattern-to-database-connections-in-php.html
Here you have my implementation maybe it is useful for you
<?php
class Utils_Sql{
private $count = 0;
private static $sqlObj = null;
/**
* #return Utils_Sql
*/
public static function getSql(){
if(self::$sqlObj===null){self::$sqlObj = new Utils_Sql();}
return self::$sqlObj;
}
private $db;
private function __construct(){
$this->db = mysql_connect(MYSQL_SERVER,DB_LOGIN,DB_PASS);
if($this->db === false){
Utils_Logging_Logger::getLogger()->log(
array("Unable to connect to DB on Mysql_Server:".MYSQL_SERVER." with login:".DB_LOGIN." and pass:".DB_PASS."!")
,Utils_Logging_Logger::TYPE_ERROR
);
}else{
if (!mysql_select_db ( DB_NAME , $this->db )) {
$sql = "CREATE DATABASE " . DB_NAME;
$this->qry($sql);
if (!mysql_select_db ( DB_NAME , $this->db )) {
Utils_Logging_Logger::getLogger()->log(
array("DB: ".DB_NAME." not found"),
Utils_Logging_Logger::TYPE_ERROR
);
}
}
}
mysql_set_charset ('utf8',$this->getConnection());
}
public function getConnection(){return $this->db;}
public function qry($sql,$errType,$errMsg=""){
$this->count++;
// Utils_Logging_Logger::getLogger()->log("<br>$sql<br>",Utils_Logging_Logger::TYPE_LOG);
$ret = mysql_query($sql,$this->getConnection());
if(mysql_error($this->getConnection())){
//Error
$msgs = array(
"mysql_error: (".mysql_error($this->getConnection()).")",
"qry: \"$sql\""
);
if($errMsg!==""){$msgs[]="$errMsg";}
Utils_Logging_Logger::getLogger()->log($msgs,$errType);
}
return $ret;
}
public function getData($sql,$errType=Utils_Logging_Logger::TYPE_ERROR){
$r = $this->qry($sql,$errType);
if($r === false){
Utils_Logging_Logger::getLogger()->log("No Sql Resource, Illegal Query!",$errType);
return false;
}
$ret = array();
while(($data = mysql_fetch_assoc($r))!==false){
$ret[] = $data;
}
if(count($ret)===1){return $ret[0];}
else if(count($ret)>1){return $ret;}
else{
$msgs = array(
"No resulset found.",
"qry: \"$sql\""
);
Utils_Logging_Logger::getLogger()->log($msgs,$errType|Utils_Logging_Logger::TYPE_WARNING);
return false;
}
}
public function getInsertId($sql,$errType=Utils_Logging_Logger::TYPE_ERROR){
$this->qry($sql,$errType);
$ret = mysql_insert_id($this->getConnection());
if(!is_numeric($ret)){Utils_Logging_Logger::getLogger()->log("mysql_insert_id is not numeric!",$errType);}
return $ret;
}
public function getDbName(){return DB_NAME;}
public function __destruct(){
// Utils_Logging_Logger::getLogger()->log("Querys count: '$this->count'",Utils_Logging_Logger::TYPE_LOG);
}
}
Interstellar_Coder is correct, you want to use a singleton/factory solution for your db connection handling. We use here at work and it serves us well.
While Interstallar_Coder's solution is valid, I wrote up a more flexible solution in response to another post.
Destroy db connections:
public function __destruct()
{
foreach (self::$dbos as $key => $dbo) {
self::$dbos[$key] = null;
}
}
More info about PDO connection management.