kickassamd Posted March 15, 2007 Share Posted March 15, 2007 I built this over a period of time just looking to see what the "experts" have to say about it... Im thinking of redoing it because my knowledge of PHP and PHP5 has changed... All coments good, bad, horrible welcome! <?php /******************************************************************************* * MySQL Database Class ******************************************************************************* * Author: Chris York (KickassAMD) * Email: admin@kickassamd.com * Website: http://www.kickassamd.com * * File: mysqldb.class.php * Version: v1.0.7 * Copyright: (c) 2006 - Chris York * You are free to use, distribute, and modify this software * under the terms of the GNU General Public License. * ******************************************************************************* * VERSION HISTORY: * * v1.0.0 [06.08.2006] - Initial Version. * v1.0.2 [10.02.2006] - Rewrote Class Completely. * - Updated Functions. * - New debugging system in place aswell. * - PHP 5 Will be required for usage of this class. * v1.0.3 [10.08.2006] - Small Changes To getLoggedQueries() function. * - Added new function execCreateDatabase(). * - Added new function execDropDatabase(). * - Added new function optimizeTable(). * v1.0.4 [10.09.2006] - Added new function execQueryFromFile(). * * v1.0.5 [1.15.2007] - Removed class constructer. New functions to set * SQL connection information via set(). * * v1.0.6 [2.6.2007] - Removed strtolower() from all query functions * as it caused issues with case sensitive information. * - Added email function to mail a error report on SQL * errors. * * v1.0.7 [3.14.2007] - Added * ******************************************************************************* * DESCRIPTION: * * This class aids in MySQL database connectivity. It was written with * my specific needs in mind. It simplifies the database tasks I most * often need to do thus reducing redundant code. It is also written * with the mindset to provide easy means of debugging erronous sql and * data during the development phase of a web application. * * The future may call for adding a slew of other features, however, at * this point in time it just has what I often need. I'm not trying to * re-write phpMyAdmin or anything. Hope you find it useful. * ******************************************************************************* * MISC NOTES: * * The function execQueryFromFile() currently does not add table prefixes * to table names, I am hopping to fix that in a later version. * * The email system uses the built in PHP mail function to send the logs. * Newer version will support sendmail or an equivalent. * You can enable it via setEmailAlerts() to true. And set() functions for * email address and subject name. ******************************************************************************* */ /** * @author Chris York (KickassAMD) * @link http://www.kickassamd.com * @version v1.0.7 * @name MySQL Server Database Class * @package Core Functions For SQL Usage */ class sqldatabase_factory { /////////////////////////////////////////////////////////////////////////// ///////////////////// Below is MySQL Configuration Values ///////////////// ///////////////////// These values cannot be set directly ///////////////// //////////////// And must be set using the set() fuctions ///////////////// /////////////////////////////// v1.0.6 //////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** * SQL Server Database Username * @var String */ private $_dbUsername; /** * SQL Server Database Password * @var String */ private $_dbPassword; /** * SQL Server Hostname \ IP Address * @var String */ private $_dbServerHost; /** * SQL Server Database Name * @var String */ private $_dbSelectName; /** * SQL Server Database Table Prefix (If Any) * @var String */ private $_dbTblPrefix; /** * Maintain Persistant Connection To SQL Server * @var boolean */ private $_dbUsePersistantConn; /** * SQL Server Connection Resource * @var Resource */ private $_dbResource; /** * SQL Server Query Logger * @var Array() */ private $_dbQueryLogger = array(); /** * SQL Server Error Logger * @var Array() */ private $_dbErrorLogger = array(); /////////////////////////////////////////////////////////////////////////// /////////////////// Below is Email Alert Configuration //////////////////// /////////////////// These values cannot be set directly /////////////////// //////////////// And must be set using the set() fuctions ///////////////// /////////////////////////////// v1.0.0 //////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** * Enable Email Alerts On SQL Errors * * @param Boolean */ private $_enabledEmailAlerts = false; /** * Email Address To Send Alerts To If Enabled * * @param String */ private $_emailAlertAddress; /** * Title of Alert email * * @param String */ private $_emailAlertSubject; /////////////////////////////////////////////////////////////////////////// ////////////////// Below is MySQL Configuration Functions ///////////////// /////////////////////////////// v1.0.6 //////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** * Set Database Username * * @param string $Username */ public function setUsername($Username) { $this->_dbUsername = $Username; } /** * Set Database Password * * @param string $Password */ public function setPassword($Password) { $this->_dbPassword = $Password; } /** * Set Database IP \ HostName * * @param string $Host */ public function setServerDSN($Host) { $this->_dbServerHost = $Host; } /** * Set Database For Use * * @param string $DbName */ public function setDatabase($DbName) { $this->_dbSelectName = $DbName; } /** * Use persistant connection to database * * @param boolean $Persistant */ public function setPersistant($Persistant = false) { $this->_dbUsePersistantConn = $Persistant; } /////////////////////////////////////////////////////////////////////////// ////////////////// Below is Email Configuration Functions ///////////////// /////////////////////////////// v1.0.6 //////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** * Enable Email Alerts * Disabled by default, only enable if needed. * * @param boolean $enable */ public function setEmailAlerts($enable) { $this->_enabledEmailAlerts = $enable; } /** * Set Email Address To Send Alerts Too * This is optional and only needs to be set if server is not on "localhost" * * @param String */ public function setEmailAlertAddress($emailAddress) { $this->_emailAlertAddress = $emailAddress; } /** * Set Email Title * * @param String $emailTitle */ public function setEmailAlertSubject($emailSubject) { $this->_emailAlertSubject = $emailSubject; } /////////////////////////////////////////////////////////////////////////// ///////////////////// Below is Functions Needed For MySQL ///////////////// /////////////////////////////// v1.0.6 //////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** * Connect To SQL Server And Select Database * * @param boolean $selectDb Select Database For Use? True | False * @return boolean */ public function getConnected($selectDb = true) { if ($this->_dbUsePersistantConn) { $this->_dbResource = @mysql_pconnect($this->_dbServerHost, $this->_dbUsername, $this->_dbPassword); } else { $this->_dbResource = @mysql_connect($this->_dbServerHost, $this->_dbUsername, $this->_dbPassword); } if ($this->_dbResource) { if ($selectDb) { if (@mysql_select_db($this->_dbSelectName)) { return true; } else { $this->logError($this->getError(), $this->getErrorNum()); return false; } } else { $this->logError("Connected To Server, No Database Selected","????"); return false; } } else { $this->logError($this->getError(),$this->getErrorNum()); return false; } } /** * Create Database On SQL Server * If $dbName is not defined, Function will use one defined in class constructor. * * @param String $dbName * @return boolean */ public function execCreateDatabase($dbName) { if ($this->_dbResource) { if ($dbName != '') { $sql = "create database `$dbName`"; } else { $sql = "create database `".$this->_dbSelectName."`"; } $this->execQuery($sql); } else { $this->logQuery($sql, "No Connection To Server", "x123"); return false; } } /** * Drop Database On SQL Server * If $dbName is not defined, Function will use one defined in class constructor * * @param String $dbName * @return boolean */ public function execDropDatabase($dbName) { if ($this->_dbResource) { if ($dbName != '') { $sql = "drop database `$dbName`"; } else { $sql = "drop database `".$this->_dbSelectName."`"; } $this->execQuery($sql); } else { $this->logQuery($sql, "No Connection To Server", "x123"); return false; } } /** * Execute SQL Query On Database * * @param String $sql * @param Boolean $execQuery (Execute Query = True) * @param Boolean $printSQL (Echo SQL To Screen = True) * @return Boolean */ public function execQuery($sql, $execQuery = true, $printSQL = false) { if ($this->_dbResource) { $sql = ltrim($sql); if ($execQuery) { if ($result = @mysql_query($sql, $this->_dbResource)) { $this->logQuery($sql, $this->getError(), $this->getErrorNum()); return $result; } else { if ($this->_enabledEmailAlerts) { $this->sendMySQLError($sql, $this->getError(), $this->getErrorNum()); } $this->logQuery($sql, $this->getError(), $this->getErrorNum()); return false; } } else { $this->logQuery($sql, "Query Not Executed!", "x124"); return false; } if ($printSQL) { echo $sql."<br />"; } } else { $this->logQuery($sql, "No Connection To Server", "x123"); return false; } } /** * Only Allow 'SELECT' SQL Statements To Be Executed On Database * * @param String $sql * @param Boolean $execQuery (Execute Query = True) * @param Boolean $printSQL (Echo SQL To Screen = True) * @return Boolean */ public function execSafeQuery($sql, $execQuery = true, $printSQL = false) { if ($this->_dbResource) { $sql = ltrim($sql); if (substr($sql, 0, 6) == 'select' || substr($sql, 0, 6) == "SELECT") { return $this->execQuery($sql, $execQuery, $printSQL); } else { $this->logQuery($sql, "Tried Executing An Unsafe Query!", "x127"); return false; } } else { $this->logQuery($sql, "No Connection To Server", "x123"); return false; } } /** * Splits A Large SQL File Into Smaller Queries And Executes Them * * NOTE: SQL File Must Not Contain Comments (Working On Fixing That) * NOTE: Function does not yet add table prefixes to queries * * @param string $file (Path to SQL file to execute from) * @param boolean $execQuery */ public function execQueryFromFile($file, $execQuery = true) { if ($fp = @fopen($file, "r")) { $fr = trim(fread($fp, filesize($file))); $sql_queries = explode(";", $fr); foreach ($sql_queries as $query) { if ($query != "") { $query = trim($query); $this->execQuery($query, $execQuery); } } } else { $this->logError("File <i>$file</i> was not found check file path and try again", "x126"); } } /** * Sets Table Prefix * * @param String $tablePrefix (Name Of Prefix) * @param String $prefixSeperator (Symbol That Separates Prefix From Table _ Is Default) */ public function setTblPrefix($tablePrefix, $prefixSeperator = "_") { $this->_dbTblPrefix = $tablePrefix.$prefixSeperator; } /** * Add Table Prefix To The Beginning Of A Table * * @param String $tableName * @return String */ public function addTblPrefix($tableName = '') { if ($tableName != '') { return $this->_dbTblPrefix.$tableName; } else { return $this->_dbTblPrefix; } } /** * Optimize Tables On SQL Server * * @param String $tableName Can be an array to optimize multiple tables at once * @return boolean */ public function optimizeTable($tableName) { if ($this->_dbResource) { if (is_array($tableName)) { foreach ($tableName as $optimize) { $sql = "optimize table `$optimize`"; $this->execQuery($sql); } } else { $sql = "optimize table `$tableName`"; $this->execQuery($sql); } } else { $this->logQuery($sql, "No Connection To Server", "x123"); return false; } } /** * Returns ID Given From 'Insert' Queries * * @return Integer */ public function getInsertId() { return @mysql_insert_id($this->_dbResource); } /** * Return Number Of Rows Returned From 'select' Query * * @param Resource $result (MySQL Query Result) * @return Integer */ public function getNumRows($result) { return @mysql_num_rows($result); } /** * Return Number Of Fields In Table * * @param Resource $result * @return integer */ public function getNumFields($result) { return @mysql_num_fields($result); } /** * Retuned Number Of Affected Rows From 'insert' or 'update' Query * * @return Integer */ public function getAffectedRows() { return @mysql_affected_rows($this->_dbResource); } /** * Get a result row as an enumerated array * * @param Resource $result (MySQL Query Result) * @return String (Array) */ public function getRow($result) { $returnArray = array(); while ($dbArray = @mysql_fetch_row($result)) { $returnArray[] = $dbArray; } return $returnArray; } /** * Fetch a result row as an associative array * * @param Resource $result (MySQL Query Result) * @return String (Array) */ public function getArray($result) { $returnArray = array(); while ($dbArray = @mysql_fetch_assoc($result)) { $returnArray[] = $dbArray; } return $returnArray; } /** * Fetch a result in enumerated & associative array * * @param Resource $result (MySQL Query Result) * @return String (Array) */ public function getBoth($result) { $returnArray = array(); while ($dbArray = @mysql_fetch_array($result, MYSQL_BOTH)) { $returnArray[] = $dbArray; } return $returnArray; } /** * Get a list of all databases available to this user * * @return String (array) */ public function getDatabaseList() { $databases = mysql_list_dbs($this->_dbResource); $returnArray = array(); while ($row = mysql_fetch_object($databases)) { $returnArray[] = $row->Database; } } /** * Get a list of all tables in a specified database * If database isnt defined, script will use one defined in class. * * @param String $database * @return string (array) */ public function getTableList($database = "") { // Use Function defined database... Or class defined if ($database != "") { $listTable = @mysql_list_tables($database, $this->_dbResource); } else { $listTable = @mysql_list_tables($this->_dbSelectName, $this->_dbResource); } // Get array list of tables $oddArray = $this->getRow($listTable); $returnArray = array(); // For() loop to make array nicer for ($i = 0; $i < sizeof($oddArray); $i++) { $returnArray[] = $oddArray[$i][0]; } return $returnArray; } /** * Get a list of all fields (columns) in a specified table. * * @param String $userTable * @return String (array) */ public function getFieldName($userTable) { $fieldList = array(); // Get all columns.. $sql = "SELECT * FROM `$userTable`"; $result = $this->execSafeQuery($sql); $count = $this->getNumFields($result); // Loop through columns and assign to an array() for ($i = 0; $i < $count; $i++) { $fieldList[] = @mysql_field_name($result, $i); } return $fieldList; } /** * Return field (column) type in a specified table * * @param String $userTable * @return String (array) */ public function getFieldType($userTable) { $fieldType = array(); $sql = "SELECT * FROM `$userTable`"; $result = $this->execSafeQuery($sql); $count = $this->getNumFields($result); for ($i = 0; $i < $count; $i++) { $fieldType[] = @mysql_field_type($result, $i); } return $fieldType; } /** * Return field (column) length * * @param string $userTable * @return integer (array) */ public function getFieldLength($userTable) { $fieldLen = array(); $sql = "SELECT * FROM `$userTable`"; $result = $this->execSafeQuery($sql); $count = $this->getNumFields($result); for ($i = 0; $i < $count; $i++) { $fieldLen[] = @mysql_field_len($result, $i); } return $fieldLen; } /** * Returns field (column) flags * ie.. primary key, auto_increment etc etc. * * @param string $userTable * @return string (array) */ public function getFieldFlag($userTable) { $fieldFlag = array(); $sql = "SELECT * FROM `$userTable`"; $result = $this->execSafeQuery($sql); $count = $this->getNumFields($result); for ($i = 0; $i < $count; $i++) { $fieldFlag[] = @mysql_field_flags($result, $i); } return $fieldFlag; } /** * Return MySQL Error String * * @return String */ private function getError() { return @mysql_error(); } /** * Return MySQL Error Number * * @return Integer */ private function getErrorNum() { return @mysql_errno(); } /** * Add A Query To Logger System * * @param string $sql * @param string $error * @param integer $errno */ private function logQuery($sql, $error = null, $errno = null) { $this->_dbQueryLogger[] = array("sql" => $sql, "error" => $error, "errno" => $errno); } /** * Add Error To Logger System * * @param string $message */ private function logError($error = null, $errno = null) { $this->_dbErrorLogger[] = array("error" => $error, "errno" => $errno); } /** * Return All Logged Queries In HTML Format * * @return String */ public function getLoggedQueries() { $return = '<table width="100%" cellspacing="1"><tr><th>Queries Logged</th></tr>'; foreach ($this->_dbQueryLogger as $query) { if ($query['error'] != null) { $return .= '<tr><td><span style="color:#ff0000;">'.htmlspecialchars($query['sql']).'<br /><b>Error number: </b>'.htmlspecialchars($query['errno']).'<br /><b>Error message: </b>'.htmlspecialchars($query['error']).'</span></td></tr>'; $return .= '<tr><td><hr color="#CCCCCC" /></td></tr>'; } else { $return .= '<tr><td><span style="color:#009933;">'.htmlspecialchars($query['sql']).'</span></td></tr>'; $return .= '<tr><td><hr color="#CCCCCC" /></td></tr>'; } } $return .= '<tr><td>Total Queries: <span style="color:#009933;">'.count($this->_dbQueryLogger).'</span></td></tr>'; echo $return; } /** * Return All Logged Errors In HTML Format * * @return String */ public function getLoggedErrors() { $return = '<table width="100%" cellspacing="1"><tr><th>Errors Logged</th></tr>'; foreach ($this->_dbErrorLogger as $error) { $return .= '<tr><td><span style="color:#ff0000;"><br /><b>Error number: </b>'.htmlspecialchars($error['errno']).'<br /><b>Error message: </b>'.htmlspecialchars($error['error']).'</span></td></tr>'; $return .= '<tr><td><hr color="#CCCCCC" /></td></tr>'; } $return .= '<tr><td>Total Queries: <span style="color:#009933;">'.count($this->_dbErrorLogger).'</span></td></tr>'; echo $return; } /** * Terminate Connection To SQL Server * */ public function terminateConn() { @mysql_close($this->_dbResource); $this->logError("Connection To The Server Was Terminated By The User", "x125"); } /////////////////////////////////////////////////////////////////////////// ////////////// Below is Functions Needed For Email Alerts ///////////////// /////////////////////////////// v1.0.0 //////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /** * Email SQL Errors to Administrator \ Or Email Address In Class. * * @return boolean */ private function sendMySQLError($sql, $error, $errno) { // Config Values $sendTo = $this->_emailAlertAddress; $subject = $this->_emailAlertSubject; // Email Headers $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n"; // // Email Body $body = '<html> <head> <title>'.$subject.'</title> <style type="text/css"> <!-- .errorDiv{ font-style:italic; font-size:smaller; color:#CC0000; } .queryDiv{ font-style:italic; font-size:smaller; color:#CC0000; } .subDiv { color:#000000; font-size:small; font-weight:normal; } .titleDiv { border: thin solid #CC0000; width: 75%; padding: 5px; } .mainDiv { text-align:center; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: small; font-weight:bold; color:#000000; } --> </style> </head> <body> <div class="mainDiv"> An SQL error has occurred and this email has been sent to notify you of the error and its description. <br /> <br /> <div class="titleDiv"> <div class="subDiv"> --- Query Details --- <div class="queryDiv"> '.$sql.' </div> <br /> --- Error Details --- <div class="errorDiv"> '.$error.' </div> <br /> --- Error Number --- <div class="errorDiv"> '.$errno.' </div> <br /> --- Time \ Date --- <div class="errorDiv"> '.date("F j, Y, g:i a").' </div> </div> </div> </div> </body> </html>'; // // Send The Email $mailer = mail($sendTo, $subject, $body, $headers); // if (!$mailer) { $this->logError("Failed sending mail", "x128"); } } } ?> Quote Link to comment Share on other sites More sharing options...
utexas_pjm Posted March 15, 2007 Share Posted March 15, 2007 After briefly looking over the class I have a few observations. -- You named your class sqldatabase_factory. While you you are certianly free to call your class whatever you want, a factory is usually a class with a set of static methods that return object instances. Calling your class a factory might confuse a developer using you class. -- In some of your methods you output HTML. I generally think this is a bad idea, as you are mixing your domain and presentation layers. When you output HTML you are dictating in your class how the output is formatted. The format of any output should be left to the presentation layer. That way you can use your class in a variety of different webapps, CLI, or GTK projects without having to modify your class. -- I think you did a good job documenting your code. Few developers, myself included, are that thorough. Best, Patrick Quote Link to comment Share on other sites More sharing options...
kickassamd Posted March 15, 2007 Author Share Posted March 15, 2007 Thank you very much for taking the time to comment! -- Yeah next one will have a diffrent naming scheme -- I see what you mean about the HTML... this was developed for my personal use at first but now im hopping to allow mass use of it. So im going to remove the HTML stuff -- Yeah documentation is also very important to me as sometimes i get lost in my own code... Quote Link to comment Share on other sites More sharing options...
kickassamd Posted March 15, 2007 Author Share Posted March 15, 2007 no one else? Quote Link to comment Share on other sites More sharing options...
JasonLewis Posted March 15, 2007 Share Posted March 15, 2007 i'm not going to go in depth on what I like/dislike about it because i am off to bed but I just quickly skimmed through it. one thing i absolutly like is your detailed documentation as mentioned above. It would be great for not new coders but more middle learners to read through that and learn from it. good job though. Quote Link to comment Share on other sites More sharing options...
per1os Posted March 15, 2007 Share Posted March 15, 2007 Very nice job. Although the one I use is strictly for MySQL and not nearly advanced, maybe I will post it in here incase someone wants to look at it /use it. Thanks for posting, I will have to look at it more in depth later see if I can't borrow some functionality. Quote Link to comment Share on other sites More sharing options...
emehrkay Posted March 16, 2007 Share Posted March 16, 2007 domain and presentation layers. what is this called exactly? i learned about it some during a web security class, but i need to read up more on the design Quote Link to comment Share on other sites More sharing options...
utexas_pjm Posted March 19, 2007 Share Posted March 19, 2007 domain and presentation layers. what is this called exactly? i learned about it some during a web security class, but i need to read up more on the design I'm not exactly sure what you're asking, but the domain layer is where you model the entities and define the logic that manages these entities. The presentation layer defines how these entities are displayed to the end user. One thing that structured OO Design affords you is the ability to use several different windows through which to interface with your program. You see this alot in Java programs, where you use the same domain layer to run a stand alone swing application, a web application via jsp, and a web service without having to change the core code in the domain layer. Best, Patrick Quote Link to comment Share on other sites More sharing options...
emehrkay Posted March 21, 2007 Share Posted March 21, 2007 domain and presentation layers. what is this called exactly? i learned about it some during a web security class, but i need to read up more on the design I'm not exactly sure what you're asking, but the domain layer is where you model the entities and define the logic that manages these entities. The presentation layer defines how these entities are displayed to the end user. One thing that structured OO Design affords you is the ability to use several different windows through which to interface with your program. You see this alot in Java programs, where you use the same domain layer to run a stand alone swing application, a web application via jsp, and a web service without having to change the core code in the domain layer. Best, Patrick Thanks for your help. What i am asking is where can I find more info on the different types of layers and what their purposes? Quote Link to comment Share on other sites More sharing options...
utexas_pjm Posted March 21, 2007 Share Posted March 21, 2007 I learned alot from the book Patterns of Enterprise Application Architecture by Martin Fowler. Best, Patrick Edit: He has a collection of articles, here: http://www.martinfowler.com/articles.html, the book is similar in style, just a lot more in depth. Quote Link to comment Share on other sites More sharing options...
emehrkay Posted March 23, 2007 Share Posted March 23, 2007 I learned alot from the book Patterns of Enterprise Application Architecture by Martin Fowler. Best, Patrick Edit: He has a collection of articles, here: http://www.martinfowler.com/articles.html, the book is similar in style, just a lot more in depth. thank you Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.