Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- insertQuery($table, $values)
- updateQuery($table, $values)
- isSqlSafe($str)
- sanitizeForQuery($str, $blacklist = NULL, $whitelist = NULL)
- escapeSpecialChars($str)
- public function setData($query)
- public function getData($query, $returnType = self::SINGLE_ROW)
- public function get_table_names($filter = NULL)
- function get_last_arraysize()
- public function get_affected_rows()
- public function get_last_insert_id()
- public function get_last_query()
- public function get_error_number()
- public function get_error()
- public function get_database_name()
- public function get_username()
- public function change_database($new_database, $username = NULL, $password = NULL)
- public function terminate()
- public static function insertQuery($table, $values)
- public static function updateQuery($table, $values)
- public static function isSqlSafe($str)
- public static function sanitizeForQuery($str, $blacklist = NULL, $whitelist = NULL)
- public static function escapeSpecialChars($str)
- private function retry_deadlock($query)
- $sql = new SqlObject();
- //Reuse the $sql object for both functions
- getNames($sql);
- getOccupation('John Doe', $sql);
- function getNames($sql = NULL){
- if($sql == NULL) { $sql = new SqlObject(); }
- $query = "SELECT `ID`,`name` FROM `table` WHERE 1";
- $result = $sql->getData($query, SqlObject::MULTI_ROW);
- $numRows = $sql->get_last_arraysize();
- for($i = 0; $i < $numRows; $i++){
- printf("Name (ID=%d): %sn", $result[$i]['ID'], $result[$i]['name']);
- }
- }
- function getOccupation($name, $sql = NULL){
- if($sql == NULL) { $sql = new SqlObject(); }
- if(!SqlObject::is_sql_safe($name)){
- throw new Exception("Unsafe user input");
- return FALSE;
- }
- $query = "SELECT `occupation` FROM `jobs` WHERE `name` LIKE '$name'";
- $result = $sql->getData($query, SqlObject::SINGLE_ROW); //Single row (assoc)
- if($result !== NULL){
- printf("Name: %s Occupation: %sn", $result['occupation']);
- }
- }
- <?php
- /*
- SqlObject.php - A SQL php helper module.
- Copyright (c) Jacob Psimos
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- * The original author's name (Jacob A Psimos) remain in this file or any
- refactored versions.
- * The original author's name (Jacob A Psimos) be included in the acknowledgements
- of the application using this library.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- class SqlObject{
- /* CONFIGURABLE VARIABLES - hard code these or use object contructor every time */
- private $SERVER_ADDRESS = 'localhost';
- private $SERVER_PORT = 3306;
- private $DATABASE_NAME = '';
- private $USERNAME = '';
- private $PASSWORD = '';
- private $MYSQLI_CHARSET = 'utf8'; //change for a custom charset
- /* PRIVATE GLOBAL VARIABLES */
- private $connection = NULL;
- private $last_count = 0;
- private $last_query = '';
- const SINGLE_ROW = 0;
- const MULTI_ROW = 1;
- const ERR_DUPLICATE = 1062;
- const ERR_DEADLOCK = 1213;
- const RETRY_DEADLOCK_ATTEMPTS = 3;
- const ACCESS_DENIED_CHANGE_USER = 1873;
- const ACCESS_DENIED_DATABASE = 1044;
- const ACCESS_DENIED_USER = 1045;
- /*
- If no username and no password and no database is provided,
- it will attempt to open a connection using the variables in the CONFIGURABLE section
- above. If your scripts will be using the same username and password and database most of the time,
- just hard code the variables above so you can just call:
- $sql = new SqlObject() and it will open without filling out the constructor every time
- */
- public function __construct($username = NULL, $password = NULL, $database = NULL){
- if($username != NULL && $password != NULL && $database != NULL){
- $this->USERNAME = $username;
- $this->PASSWORD = $password;
- $this->DATABASE = $database;
- }
- $this->connection = new mysqli($this->SERVER_ADDRESS, $this->USERNAME, $this->PASSWORD, $this->DATABASE_NAME, $this->SERVER_PORT);
- if($this->connection->connect_error){
- throw new Exception("SqlObject::construct() Connection error: " . $this->connection->connect_error);
- }else{
- mysqli_set_charset($this->connection, $this->MYSQLI_CHARSET);
- if($this->connection->error){
- throw new Exception("SqlObject::construct() Charset Error: " . $this->connection->error);
- }
- }
- }
- /*
- Use this function when a query is INSERT, UPDATE, etc
- where you know the SQL query is not going to return a row
- */
- public function setData($query){
- if($this->connection){
- $result = $this->connection->query($query);
- $this->last_query = $query;
- if($result == FALSE){
- /* How to handle certain SQL errors */
- switch($this->connection->errno){
- case self::ERR_DEADLOCK:
- return $this->retry_deadlock($query);
- break;
- case self::ERR_DUPLICATE:
- return FALSE;
- break;
- case self::ACCESS_DENIED_CHANGE_USER:
- throw new Exception($this->connection->error);
- break;
- case self::ACCESS_DENIED_USER:
- throw new Exception($this->connection->error);
- break;
- case self::ACCESS_DENIED_DATABASE:
- throw new Exception($this->connection->error);
- break;
- default:
- //file_put_contents('debug.txt', $this->connection->errno);
- throw new Exception($this->connection->error);
- break;
- }
- } //end error catching switch
- return TRUE; //Successful
- }
- return FALSE; //normally not reached
- }
- /*
- This this to retrieve rows using an SQL query.
- When returnType is SINGLE_ROW, only one row is returned even if there are many.
- When returnType is MULTI_ROW, an array of rows is returned.
- NULL is returned if the query returns nothing.
- */
- public function getData($query, $returnType = self::SINGLE_ROW){
- if(!$this->connection){
- throw new Exception('The Database connection is broken' . "n" . $query);
- }
- /* Run the provided query, if the query is invalid the return will be FALSE */
- $datum = $this->connection->query($query);
- $this->last_query = $query;
- if(!$datum){
- throw new Exception("SqlObject::getData() Error: " . $this->connection->error);
- }
- /* Single row (0) returns an associative array of the selected row */
- /* Multi row (1) returns an array of associative array(s) from the query */
- switch($returnType){
- case self::SINGLE_ROW:
- $result = $datum->fetch_assoc();
- $datum->free();
- return $result;
- break;
- case self::MULTI_ROW:
- $this->last_count = 0;
- $returnData = array();
- while($nextRow = $datum->fetch_assoc()){
- array_push($returnData, $nextRow);
- $this->last_count++;
- }
- $datum->free();
- if($this->last_count > 0){
- return $returnData;
- }
- break;
- default:
- throw new Exception("Invalid argument for setData(); expected returnType is invalid");
- break;
- }
- return NULL;
- }
- /*
- Returns an array of strings containing all of the table names in the current database
- */
- public function get_table_names($filter = NULL){
- $query = $filter != NULL ? "SHOW TABLES LIKE '$filter'" : 'SHOW TABLES';
- $datum = $this->connection->query($query);
- //$this->last_query = $query;
- if(!$datum){
- throw new Exception($this->connection->error);
- }
- $names = array();
- while($nextRow = $datum->fetch_array(MYSQLI_NUM)){
- if(count($datum) > 0){
- array_push($names, $nextRow[0]);
- }
- }
- $datum->free();
- return $names;
- }
- /* gets the size of the last returned array from getData */
- function get_last_arraysize(){
- return $this->last_count;
- }
- /* gets the number of rows affected by the last query */
- public function get_affected_rows(){
- return $this->connection->affected_rows;
- }
- /* returns the ID of the last INSERT query
- NOTE this does not return the ID from an UPDATE query */
- public function get_last_insert_id(){
- return $this->connection->insert_id;
- }
- /* returns the last query that was executed */
- public function get_last_query(){
- return $this->last_query;
- }
- /* pass back the sql error number */
- public function get_error_number(){
- return $this->connection->errno;
- }
- /* return the sql error message */
- public function get_error(){
- return $this->connection->error;
- }
- /* get the current database name */
- public function get_database_name(){
- return $this->DATABASE_NAME;
- }
- /* get the current username */
- public function get_username(){
- return $this->USERNAME;
- }
- /* attempt to connect to a new database with optional different credentials */
- public function change_database($new_database, $username = NULL, $password = NULL){
- if(!$this->connection){
- throw new Exception("change_database($new_database) failed because of a broken connection");
- }
- if($this->connection->change_user($username != NULL ? $username : $this->USERNAME,
- $password != NULL ? $password : $this->PASSWORD, $new_database)){
- $this->DATABASE_NAME = $new_database;
- $this->USERNAME = $username != NULL ? $username : $this->USERNAME;
- $this->PASSWORD = $password != NULL ? $password : $this->PASSWORD;
- }else{
- throw new Exception($this->get_error());
- }
- }
- /* end the sql connection */
- public function terminate(){
- if($this->connection){
- $this->connection->close();
- unset($this->connection);
- }
- }
- /*
- Returns an SQL query string given a table name and an associative array
- of key -> value items to be included in the query
- */
- public static function insertQuery($table, $values){
- $query = "INSERT INTO `$table`(";
- $firstpart = '';
- $lastpart = '';
- $len = count($values);
- $i = 0;
- foreach($values as $key => $value){
- $firstpart .= ($i < $len - 1) ? "`$key`," : "`$key`) VALUES(";
- if(is_numeric($value) && $value[0] != '+'){
- $lastpart .= ($i < $len - 1) ? "$value," : "$value)";
- }else{
- $lastpart .= ($i < $len - 1) ? "'$value'," : "'$value')";
- }
- $i++;
- }
- return ($query . $firstpart . $lastpart);
- }
- /*
- Returns an SQL UPDATE query string given a table name
- and an associative array of key -> value pairs for the update parameters.
- It is up to the programmer to append the WHERE clause (if needed) to the returned string
- */
- public static function updateQuery($table, $values){
- $query = "UPDATE `$table` SET ";
- $num = count($values);
- $i = 0;
- foreach($values as $key => $value){
- if(is_numeric($value) && $value[0] != '+'){
- $query .= "`$key`=$value";
- }else{
- $query .= "`$key`='$value'";
- }
- if($i < $num - 1){
- $query .= ', ';
- }
- $i += 1;
- }
- return $query;
- }
- /*
- A light scan of a string for common SQL injection commands.
- returns true or false if the string contains a commands
- *** This function does not detect all types of SQL injection ***
- *** Combine this with sanitizeForQuery() for stronger protection ***
- */
- public static function isSqlSafe($str){
- $select_safe = stripos($str, "SELECT `") === FALSE && stripos($str, "SELECT *") === FALSE;
- $insert_safe = stripos($str, "INSERT INTO `") === FALSE && stripos($str, "INSERT INTO *") === FALSE;
- $update_safe = stripos($str, "UPDATE `") === FALSE && stripos($str, "UPDATE *") === FALSE;
- $join_safe = stripos($str, "JOIN `") === FALSE && stripos($str, "INNER JOIN `") === FALSE;
- return $select_safe && $insert_safe && $update_safe && $join_safe && $bogus_quote;
- }
- /*
- Takes a string containing possibly harmful SQL text and characters and
- returns a sanitized version with those items removed.
- $blacklist - an array of strings that should be included in the sanitization default blacklisted
- $whitelist - an array of strings that should be whitelisted
- */
- public static function sanitizeForQuery($str, $blacklist = NULL, $whitelist = NULL){
- //These phraises are to be removed from the resulting value
- $blacklist1 = array(
- '<?php',
- '?>',
- 'x',
- );
- $str = SqlObject::escapeSpecialChars($str);
- /* Loop through all of the blacklisted phraises and remove them */
- foreach($blacklist1 as $blockedchar){
- if($whitelist !== NULL){
- if(!in_array($blockedchar, $whitelist)){
- $temp = str_replace($blockedchar, '', $str);
- unset($str);
- $str = $temp;
- }
- }else{
- $temp = str_replace($blockedchar, '', $str);
- unset($str);
- $str = $temp;
- }
- }
- if($blacklist !== NULL){
- foreach($blacklist as $filter){
- $temp = str_replace($filter, '', $str);
- unset($str);
- $str = $temp;
- }
- }
- return $str;
- }
- /*
- Escape single quote, double quote, percent, underline (_)
- also replaces multiple consecutive \ slashes with a single one
- so escapes dont get messed up
- */
- public static function escapeSpecialChars($str){
- $temp = preg_replace("/\'+/", "'", $str);
- $temp = preg_replace('/"+/', '"', $temp);
- $temp = preg_replace('/%+/', '%', $temp);
- $temp = preg_replace('/_+/', '_', $temp);
- return preg_replace('/\+/', '\', $temp);
- }
- /* automatically close the connection when the object is disposed */
- public function __destruct(){
- if(isset($this->connection)){
- $this->connection->close();
- unset($this->connection);
- }
- }
- /* reattempt to run the query that caused a deadlock */
- private function retry_deadlock($query){
- for($i = 0; $i < self::RETRY_DEADLOCK_ATTEMPTS; $i++){
- $result = $this->connection->query($query);
- if($result){
- return TRUE;
- }
- sleep(1);
- }
- return FALSE;
- }
- } /* end class */
- ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement