 |
Account Login
|
 |
 |
Latest Articles
|
 |
 |
IRC Channel
|
 |
 |
Associates
|
 |
 |
Associates
|
 |
|
 |
 |
|
 |
11-28-2007, 10:53 PM
|
#1 (permalink)
|
|
The Addict
Join Date: Nov 2007
Posts: 264
Thanks: 2
|
First Generic Class
Well I've been wanting to get a generic class done for a while and I think I've finally finished one that covers the basics, and I'd like some input on which functions to optimize and the such...all help is appreciated
PHP Code:
<?
class core {
//contains the main mysql abstraction layer var $db; //tags to be searched for var $tags = array(); //all the replacement for the tags var $reps = array(); //the neccesary site info var $siteinfo = array(); //make a holding variable for out content var $rcontent; //the general content holder.. var $content; //holds the session and cookie names var $secinfo = array('cookie'=>'TlcFinalCMS','session'=>'TlcFinalCMSession'); //holds member data var $member; //holds language var $language;
/*====================================================+ | The General Purpose functions |=====================================================*/
//the constructor function function core() { $this->db = NewTlcDB(DB_HOST,DB_USER,DB_PASS,DB_TABLE); //determine the site info crap.. $this->siteinfo = $this->db->Execute("SELECT `url`,`title`,`skin`,`lan`,`defaultmod` FROM `site_config`"); $this->siteinfo = $this->siteinfo->fields; //load the language file. $this->LoadLanguage($this->siteinfo['lan']); //build the tags array.. $this->tags = array( '<[siteurl]>', '<[skinurl]>', '<[title]>', '<[gentime]>', '<[content]>', '<[cmp(', ')]>' ); //build all there replacements. $this->reps = array( $this->siteinfo['url'], $this->siteinfo['url'] . 'template/' . $this->siteinfo['skin'], '<?=$this->siteinfo[\'title\']; ?>', '<?=$this->siteinfo[\'gentime\']; ?>', '<? $this->PageCreate(); ?>', '<? $this->ComponentPlace(', '); ?>' ); //check all the member atributes if($this->CheckCreds() || !$this->SessionExists()) { $this->SetUpMember(); } } //creates random values function GenVal($len=40) { //set all variables $val = ''; $count = 0; //start the count while($count < $len) { //use this method.. $val .= chr(0x3 . rand(0,80)); //increase the count $count++; } return $val; } //the open function, just opens file and returns there content function open($file) { //check if the file exists if(file_exists($file)) { //it does, so open it in read mode $f = fopen($file,'r'); //start the loop to get contents while(!feof($f)) { $buff .= fgets($f,4096); } //return the material return $buff; } } //it doesnt APPEND to files, it writes them anew function write($file,$cont) { //set it up then $f = fopen($file,'w'); //append to the file fwrite($f,$cont); return true; } //compares two strings..um, don't really know what I can use it for but w/e function Compare($str1,$str2) { //take the string lengths of both $len = strlen($str1); $len2 = strlen($str2); //if they aren't equal if($len !== $len2) { //set it to the biggest $len = (strlen($len) > strlen($len2)) ? $len : $len2; } //grab the 1% value and set the total and count variables $percent = 100 / $len; $total = 0; $count = 0; //start the loop while($len !== $count) { //check if they're equal if(substr($str1,$count,1) == substr($str2,$count,1)) { //add the total $total += $percent; } //increase the count $count++; } //return a rounded down result return floor($total); } //this is where we fetch the componenets function ComponentPlace($value='') { // } //ok here is the page create.. function PageCreate() { //hell we include it.. $this->Mictime(); //ok now get the data $mod = !empty($_GET['mod']) ? $_GET['mod'] : $this->siteinfo['defaultmod']; $mod = $this->MySQLSecure($mod); $mod = $this->db->Execute(sprintf("SELECT `folder`,`active` FROM `modules` WHERE `name`='%s'",$mod));
$do = !empty($_GET['do']) ? $_GET['do'] : 'main'; //check if it's empty if(empty($mod->fields['folder'])) { $this->Mictime(); echo($this->language['nomod']); return false; } //check if it's in a non-active state and thus have to be an admin if($mod->fields['active'] == 0) { //they're not an admin if(!$this->Access(3)) { //display a no mod error $this->Mictime(); echo($this->language['nomod'].'e'); } else { //the are so include the ifle $this->Mictime(); include(ROOT . '/modules/' . $mod->fields['folder'] . '/' . $do . '.php'); } } else { //guess it is active so include the file either way $this->Mictime(); include(ROOT . '/modules/' . $mod->fields['folder'] . '/' . $do . '.php'); } } //an ease of use function for mysql_real_string_escape function MySQLSecure($text) { return mysql_real_escape_string($text,$this->db->connectionID); } //generate forms..it only works within the site,It's EXTREMELY basic.. function FormGenerate($to,$values=array(),$echo=false) { //set up the form and create the action $data = '<form method="post" action="'.$this->siteinfo['url'] . $to.'"> <table>'; //start the loop, this method is supposed to be more efficient while(list(, $v) = each($values)) { //create the table and such $data .= ' <tr> <td><label for="'.$v.'">'.$v.'</label><td> <td><input name="'.$v.'" id="'.$v.'" value="" size="30" maxlength="255" type="text"></td> </tr>'; } //finish it all off $data .= '<tr><td><input value="submit" type="submit"></td></tr></table>'; //return it all if($echo) { echo($data); }else{ return $data; } } function Void() { //do nothing } //load stuff from language file function LoadLanguage($file) { if(file_exists(ROOT . '/language/' . $file . '.php')) { include(ROOT . '/language/' . $file . '.php'); $this->language[] .= $lan; unset($lan); } } //Generationg time function function Mictime() { //$this->siteinfo['gentime'] = empty($this->siteinfo['gentime']) ? microtime() : microtime() - $this->siteinfo['gentime']; //check if the variable was alrady filled if(empty($this->siteinfo['gentime'])) { //it wasnt so fille it $this->siteinfo['gentime'] = microtime(); } else { //minute the bigger microtime agaist the smaller to get out time $this->siteinfo['gentime'] = microtime() - $this->siteinfo['gentime']; } } //activate the tinymce editor function tinyeditor($to) { $to = $this->siteinfo['url'] . $to; include(ROOT . '/kernal/resources/tinyMCE.php'); }
/*====================================================+ | Template portion of the API |=====================================================*/ function construct($file,$cache=true,$name='',$case=true) { $start = microtime(); //ok does the file exists? if(file_exists($file)) { //ok now that we know it does exists..call it up $ofile = $this->open($file); //prepare the tags and replacements $t = reset($this->tags); $r = reset($this->reps); //look at the case $strf = $case ? 'str_replace' : 'str_ireplace'; //now set the loop while($t !== false or $r !== false) { $ofile = $strf($t,$r,$ofile); $t = next($this->tags); $r = next($this->reps); } //now thats it done, does he want it cached? if($cache) { $end = microtime(); $total = $end - $start; //he does so lets give it a name.. $this->write(SYSTEM_CACHE . '/' . $name . '.php',$ofile . '<!--' . date('Y:m:d'). ' ' . $total . '--->'); return true; } else { //he didn't want it cached..add it to the place holder $this->rcontent = $ofile; } //empty out the ofile unset($ofile); } } //function to add values to the rep and tag array function addTags($tag,$rep) { //check for any empty values if(!empty($tag) || !empty($rep)) { $this->tags[] .= $tag; $this->reps[] .= $rep; } } //it fetches the skin function TempSetUp() { //does the skin actually exists? if(file_exists('cache/skincache.php')) { //it does so include it } else { //it doesn't so have it construction $this->construct(ROOT . '/template/' . $this->siteinfo['skin'] . '/index.php',true,'skincache'); } include('cache/skincache.php'); }
/*====================================================+ | Member portion of the API |=====================================================*/
//premilinrary credential checks...see if the user is logged in..nothing more function CheckCreds() { //check if the session exists and it's an array if($this->SessionExists()) { return true; } //check if a cookie exists and it's not empty if(isset($_COOKIE[$this->secinfo['cookie']]) && strlen($_SESSION[$this->secinfo['cookie']]) > 0) { return true; } } //check if a session exists function SessionExists() { if(isset($_SESSION[$this->secinfo['session']]) && is_array($_SESSION[$this->secinfo['session']])) { return true; } return false; } //assuming they've proper session info or cookie info..lets make em up function SetUpMember($user='') { //user is empty.. if(empty($user)) { //does the session even exists? if(!$this->SessionExists()) { //take the cookie's data $data = $_COOKIE[$this->secinfo['cookie']]; //now preform the SQL statement $sql = $this->db->Execute("SELECT `username`,`email`,`rank` FROM `users` WHERE `hash`='".$data."'"); //set it as a session $_SESSION[$this->secinfo['session']] = $sql->fields; $s = $this->db->GetOne(sprintf("SELECT `numeric` WHERE `name`='%s'",$sql->fields['rank'])); $_SESSION[$this->secinfo['session']]['rank'] = $s; } } else { //sanitize user incase it's an input $user = $this->MySQLSecure($user); //I guess they want it for a specific ember $sql = $this->db->Execute(sprintf("SELECT `username`,`email`,`rank` FROM `users` WHERE `username`='%s'",$user)); //now set the session.. $_SESSION[$this->secinfo['session']] = $sql->fields; $s = $this->db->GetOne(sprintf("SELECT `numeric` FROM `user_rank` WHERE `name`='%s'",$sql->fields['rank'])); $_SESSION[$this->secinfo['session']]['rank'] = $s; //well the cookie doesn't exists obviously..so lets create it $val = $this->GenVal(255); setcookie($this->secinfo['cookie'],$val, time() * 360000); $this->db->Execute(sprintf("UPDATE `users` WHERE `usersname`='%s' SET `hash`='%s'",$user,$val)); } $this->member = $_SESSION[$this->secinfo['session']]; } //Regisers users function Register($user,$pass,$email) { //sanitize the variables into a clean array $info = array( 'user'=>$this->MySQLSecure($user), 'pass'=>$this->MySQLSecure($pass), 'email'=>$this->MySQLSecure($email) ); //ok now make the checks $c = $this->db->GetOne(sprintf("SELECT `email` FROM `users` WHERE `username`='%s'",$info['user'])); if(!empty($c)) { $var = ($c == $info['emai']) ? 01 : 00; return $var; } $c = $this->db->GetOne(sprintf("SELECT `username` FROM `users` WHERE `email`='%s'",$info['email'])); if(!empty($c)) { return 01; } //ok now create the statement $hash = $this->MySQLSecure($this->GenVal(126)); $this->db->Execute( sprintf("INSERT INTO `users`(`id`,`username`,`password`,`passhash`,`email`) VALUES('','%s',MD5(CONCAT('%s','%s')),'%s','%s')", $info['user'],$info['pass'],$hash,$hash,$info['email']) ); return true; } //Logs in the people function Login($user,$pass) { //sanitize variables $info = array('user'=>$this->MySQLSecure($user),'pass'=>$this->MySQLSecure($pass)); $hash = $this->db->GetOne(sprintf("SELECT `passhash` FROM `users` WHERE `username`='%s'",$info['user'])); $h = $this->db->GetOne(sprintf("SELECT `username` FROM `users` WHERE `password`='%s'",md5($pass.$hash))); //check if it's write if($h == $info['user']) { $this->SetUpMember($info['user']); return true; } else { return false; } } //destroys the sessions and empties the cookie function Logout($user) { //obvious...it gets rid of the current session session_destroy(); //empties cookie and se hash equal to zero setcookie($this->secinfo['cookie'],'',time() * 360000); $this->db->Execute(sprintf("UPDATE `users` WHERE `username`='%s' SET `hash`='0'",$user)); } //are they even logged in? function no_guest($boink=false) { //check if the sesison exists if(!$this->SessionExists()) { //it doesnt so check if the is empty.. if(strlen($_COOKIE[$this->secinfo['cookie']]) == 0) { if($boink) { header('Location: http://google.com'); } //it is return a false.. return false; } } //everything checked out so send it out as true. return true; } //check if they have permission to view the site function Access($lvl=0) { //check if they are logged in first of all if(!$this->no_guest()) { //they are..so set it up $this->SetUpMember(); //check if the sesion still doesn't exists if(!$this->SessionExists()) { return false; } } //now check to if(is_numeric($this->member['rank'])) { $ret = ($this->member['rank'] <= $lvl) ? true : false; return $ret; } return false; } function KickAccess($lvl=0) { if(!$this->Access($lvl)) { header('Location: ' . $this->siteinfo['url']); } }
}
This is my accompanying MySQL class
PHP Code:
<?
function NewTlcDB($host,$user,$pass,$db) { return new TlcDB($host,$user,$pass,$db); }
class TlcDB { private $querycount; private $queryID; public static $connectionID; private $numrows; private $numfields; var $fetchMode = MYSQL_ASSOC; var $db; function TlcDB($uHost, $uUser, $uPass, $uDb, $Sec=true) { if (mysql_connect($uHost, $uUser, $uPass)) { $this->connectionID = mysql_connect($uHost, $uUser, $uPass); }else{ return false; } if (mysql_select_db($uDb, $this->connectionID)) { $this->db = $uDb; } mysql_close(); if($Sec) { $this->escape = $Sec; } } function SetDB($db) { $this->db = $db; } function _query($sql) { $this->queryID = mysql_query($sql,$this->connectionID); $this->querycount++; return $this->queryID; }
function init() { $this->numrows = @mysql_num_rows($this->queryID); $this->numfields = @mysql_num_fields($this->queryID); } function Execute($sql) { $this->_query($sql); $this->init(); $d = new RecordSet($this->queryID); return $d; } function GetOne($sql) { $s = $this->_query($sql); $s = @mysql_fetch_array($s,MYSQL_ASSOC); if(empty($s)) { return false; } return reset($s); } function GetRow($sql) { $s = $this->Execute($sql); $e = array(); $i = 0; while(!$s->EOF) { $e[$i] = reset($s->fields); $s->MoveNext(); $i++; } return $e; } function affectedRow() { return mysql_affected_rows($this->connectionID); }
function Databases() { $d = mysql_list_dbs($this->connectionID); $a = array(); $i = 0; $m = mysql_num_rows($d); while ($i < $m) { $b = mysql_tablename($d, $i); if ($b != 'mysql') { $a[] = $b; } $i++; } return $a; }
function ErrNo() { if (empty($this->connectionID)) { return @mysql_errno(); } return @mysql_errno($this->connectionID);
}
function ErrMsg() { if (empty($this->connectionID)) { return @mysql_error(); } return @mysql_error($this->connectionID); }
function Description() { return $this->GetOne("SELECT version()"); } function AlphabatizeColumn($sql, $col, $upper = false) { $p = $upper ? 'toupper' : 'tolower'; $p = 'str'.$p; $d = $this->Execute($sql); $mast = array(); $i = array(); while (!$d->EOF) { $str = $p(substr($d->fields[$col], 0, 1)); $mast[$str][$i[$str]] = $d->fields[$col]; $i[$str]++; $d->MoveNext(); } return $mast; }
function AffectedRows() { return mysql_affected_rows($this->connectionID); }
}
class RecordSet extends TlcDB { var $fields = array(); var $fieldCount; var $EOF; var $queryID;
function RecordSet($query) { $this->fields = @mysql_fetch_array($query, $this->fetchMode); $this->queryID = $query; $this->fieldCount++; } function basicquery($sql) { return $this->_query($sql); }
function MoveNext($stop=false) { if (@$this->fields = mysql_fetch_array($this->queryID, $this->fetchMode)) { $this->fieldCount++; if($stop > 0) { if($stop >= $this->fieldCount) { $this->EOF = true; return false; } } return true; } if (!$this->EOF) { $this->fieldCount++; $this->EOF = true; } return false; } } ?>
|
|
|
|
11-29-2007, 03:58 AM
|
#2 (permalink)
|
|
La Vida es Sueño
Join Date: Sep 2007
Location: Oldham
Posts: 2,280
Thanks: 90
|
One problem that immediately springs up is the fact that you haven't used any scopes on your functions. For instance, you've prefixed some functions, such as _query, with the underscore, which tends to be indicative of a private function by Zend Framework standards. However, no scope has been set.
The scopes consist of the following:
- Private: Only members in the same class has access.
- Protected: Only members of the same class and those extended have access.
- Public: Everybody has access (default)
I'll have myself a good read through tomorrow though and see what I can pick out. It does look like a good attempt nonetheless.
__________________
The man who comes back through the Door in the Wall will never be quite the same as the man who went out.
|
|
|
11-29-2007, 11:04 AM
|
#3 (permalink)
|
|
The Addict
Join Date: Nov 2007
Posts: 264
Thanks: 2
|
Thanks, wild. I never bothered learning any standards, I should look into that.
|
|
|
|
11-29-2007, 02:17 PM
|
#4 (permalink)
|
|
The Reckoner
Join Date: Sep 2007
Posts: 437
Thanks: 22
|
Nice start TlcAndres, you seem to have grasped the basic concepts of classes just fine. Now for the problems - I'm analyising the design and structure of your classes here, not the code it contains (I'll let someone else comment on that)
The first problem would be the cohesiveness of the "core" class - that class has so many different tasks it's near impossible to see what the object is responsible for. Good object orientated design suggests that your classes should be loosely coupled and cohesive. A good rule of thumb is "one class, one task". I'm not saying you should stick to these strictly, just being aware of them will improve your code which will in turn make the code easier for other people to understand.
I only flicked through, but I noticed you have separated different parts of the core class into "groups" - indicated by the comments. I would suggest splitting these groups into separate classes, for example, you have some methods specific to members, I would refactor the code and take these methods out of the core class, placing them into their own class.
It just makes things easier and more logical. I also find it helps to think of things in terms of responsibilities, for example, what is the core class responsible for? Each class should have a clear cut responsibility, if you can't figure out what that is (or if the class has many responsibilities) then you should reconsider your object design.
So, my first suggestion for improvement would be to refactor the class, that is, pull out all the "method groups" and place them in their own class.
__________________
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
|
|
|
|
11-29-2007, 05:19 PM
|
#5 (permalink)
|
|
The Prestige
Join Date: Oct 2007
Location: Manchester, UK
Posts: 854
Thanks: 32
|
The only thing i can see is the 'var' keyword, which in php5 was deprecated in favor of visibility scope identifiers (as pointed out by wildhoney) but left in php5 for backward compatibility.
Also as Karl says your core does seem a little confused about its purpose, i.e. having the
HTML Code:
MySQLSecure($text)
function inside the core, whereas it could be in the mysql class and also templating functions within the core too, but a good start I'd say
__________________
mysql> SELECT * FROM `users` WHERE `users`.`clue` > 0;
Empty set (0.00 sec)
|
|
|
|
11-29-2007, 05:28 PM
|
#6 (permalink)
|
|
The Wanderer
Join Date: Nov 2007
Posts: 18
Thanks: 3
|
I agree with Karl ... You need to step back and look at the individual roles/responsibilities you are trying to accomplish.
I typically follow the following breakdown when it comes to data drive web site classes:
1. configuration - a place to store constant data (db connection info, etc)
2. Generic database access class (something I can pass queries to and will return results, errors, etc)
3. Data access objects (these are classes that typically represent tables in the database: tags, page_content, users,etc)
the DAOs have a common interface that allows for:
- Make() returns an empty dao object ( not a datarow yet)
- Save( $obj ) inserts or updates the dao object
- Load( $id ) returns a dao object that does represent a datarow based on the primary key (Id) passed
- Delete( $id ) deletes the data row
4. Finally I create a business object to pull things together
you may have methods such as: GetTags( $pageId ) or LoadPageContent( $pageId )
this business object utilizes the multiple daos and provides more automated methods for the webpage to use instead of dealing with daïs and all the logic in the actual web page.
This approach is good practice and is generically, although not strictly, described by MVC: Model, View, Control be describes the separation of application logic into separate layers.
I hope this helps you continue on your quest for the Generic Class!
Brad
Last edited by bmicallef : 11-29-2007 at 05:31 PM.
Reason: typing on an iPhone is not perfect!
|
|
|
11-29-2007, 05:46 PM
|
#7 (permalink)
|
|
The Acquainted
Join Date: Nov 2007
Posts: 127
Thanks: 14
|
bmicallef: Could you tell me more about your database class?
To the OP: Try sticking to a consistent coding style. I see a bunch of different variables, function names and code logic with different conventions. :)
|
|
|
|
11-30-2007, 11:49 AM
|
#8 (permalink)
|
|
The Wanderer
Join Date: Nov 2007
Posts: 18
Thanks: 3
|
gcbdm,
I'd be happy to share what I am doing!
I create a CLASS that will act as a generic database interface
public class myDB()
{}
NOTE: I'm pretty sure DB() is defined in the Zend framework and should be considered reserved ...
The class contains a number of private attributes:
private $_connection = null;
private $_rows_affected = 0;
private $_last_inserted_id = 0;
private $_results = null;
private $_error_message = null;
private $_error_number = null;
I use the __construct() method to set the connection string (I pull login and server variables from a separate configuration class e.g. myConfig::dbUsername, etc.) and I open the connection.
The __construct() method contains error handling that will SET the $_error_number and $_error_message attributes in the event of a failure.
I then have a public method called Query( $sql ) that allows me to pass SQL statements directly.
The Query() CLASS returns a bool (True or False) if the query was successful, but sets the above mentioned private attributes.
NOTE: Like __construct(), this method also contains error handling logic.
Finally, I have a series of Accessors that allow me to GET the values from my private attributes:
public function GetResults()
{
results $this->_results;
}
... etc.
So to use this you do something like this:
$sql = "SELECT * FROM mytable WHERE somevalue = 1";
$db = new myDB();
if ( $db->Query( $sql ) )
{
doSomething( $db->GetResults() );
}
I hope this helps!
Brad
|
|
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Hybrid Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|