наши рабочие классы для работы с бд

Статус
В этой теме нельзя размещать новые ответы.
Мда... Книжек обчитался или где? С какого перепугу бизнес-логика попала в прослойку субд? Типа умными словами забросать решил. Ну-ну. Не рассказывай об этом никому - засмеют.

Если фильтрация ввода не защищает от инъекции, то что по-твоему защищает? Бойцы невидимого фронта? А ну да, это ж нужен еще отдельный класс для фильтрации ввода. Ну так и выложил бы его вместе с классом логгера. А то выложил кусок и удивляется что кому-то что-то не понравилось.

P.S. htmlspecialchars из своего поста оставляю. А то тебе цепляться некчему будет.
 
Давайте определимся с понятием фильтрация и будем спорить дальше.

В "стандартных", Для просмотра ссылки Войди или Зарегистрируйсяметодах SQL-инъекций, используются как-раз таки кавычки, для обрыва серии строк и вставки своего кода. Помочь-то помогает, только вот насколько оптимален данный подход - большой вопрос.

Стоит, однако, заметить, что функциями удаления/экранирования нежелательных данных изначально являются mysql_escape_string, mysql_real_escape_string, addslashes :)
 
А я и не спорил. Просто некоторые цепляются к словам. Для чего мы пользуем htmlspecialchars? Для фильтрации ввода. А для чего mysql_escape_string и иже с ним? Тоже для фильтрации ввода. Я (когда надо) еще пользую регексп для проверки языка (например пропускаем только украинский). Указав htmlspecialchars я имел ввиду фильтрацию вообще и, как мне казалось (и кажется) из контекста это было ясно всем (как выяснилось не всем). Почему господину Slayter-у захотелось выпендрится мне не понять. Вот такие дела...
 
Люди, а объясните мне глупому, зачем вообще эти классы нужны? Ну то есть почему бы нам не писать прямо в коде
mysql_query() вместо $moysuperclass->query(); Чем это хуже?

А, да, знаю. Тяжело будет мигрировать на другую СУБД.
Вы много вообще использовали субд, кроме мускула?
Как правило если субд - не мускул, то об этом известно еще задолго до начала проекта. И шанс, что так будет, а особенно среди nulled тусовки, - он вообще-то говоря ничтожен.
Так зачем городить огород?
 
Simpson, чё за бред ты несёшь? "бизнес-логика попала в прослойку субд" -- сам-то понял чо сказал? Любая работа с данными (а прослойка для субд именно с ними и работает) есть бизнес-логика приложения. По GoF она относится к модели в паттерне MVC, адептом которого я и являюсь :)

К фильтрации содержимого посредством htmlspecialchars прибегают только начинающие разработчики (ню-ню, пожалуйста, применяй его в админке, например:D, чтобы пресечь использование html'я некой группой пользователей), а те, у которых есть опыт разрешают пользователю вводить определённые html теги (или предоставляют для этого визуальный редактор).

Ну а фильтрацией занимаются отдельные валидаторы (POSIX, PCRE -- дело вкуса + для некоторых типов данных они и не нужны, хватает стандартных проверок) :) Ну а если php > 5.2.0 и стоит PECL filter, то прекрасное решение всех этих танцов с бубнами есть filter_var();, что вообще и не является проблемой, т.к. я думаю тут мало кто пользуется шаред-хостингами. VPS сейчас за копейки можно приобрести в пользование и настроить всё как надо. Сам пользуюсь регулярными выражениями, т.к. некоторые клиенты предпочитают размещать свои сайты таки на каком-нибудь уёбищном хостинге. С этим ничего не поделаешь, а жаль, конечно :(

Защитой от SQL-инъекций должна заниматься сама прослойка для работы с базой данных (простого mysql_escape_string для этого вполне хватает). Нет, ну если не так, то какой идиот будет ручками всё обрабатывать перед передачей классу? :(
 
Я несу бред?... Мда. Твое заблуждение насчет бизнес-логики лечится вдумчивым чтением википедии.


В многоуровневых (многослойных) информационных системах этот уровень взаимодействует с нижележащим уровнем инфраструктурных сервисов (Infrastructure Layer), например, интерфейсом к базе данных или файловой системе
ну и конечно же

Насчет GoF - тут загадочная ситуация. В их книге описывается 23 паттерна, но ничего такого что ты тут пишешь, увы, нет. Собственно интересно узнать кто-куда-чего-относит. Можешь пару цитат привести для примера (желательно с номером страницы)?

Насчет остального - где-то согласен, где-то нет. Но поскольку тема ушла в сторону смысла в дальнейшем обсуждении не вижу.
 
Во блин демагогию со спорами развели :D

Моя класса для работы с БД использующая PDO

PHP:
class Datasource_gopher extends PDO {
	
	const
				_QUOTE_TABLE	= 1,
				_QUOTE_COL		= 2,
				_QUOTE_BOTH		= 3,
				_QUOTE_NONE		= 0;
				
	protected $db_prefix = null;
	
	protected $invalid_format = 'provided %1$s name "%1$2" is not a valid name. Must contain "A-Z", "a-z", "0-9", "_", "-" only, and begin with an Alpha char';
	// constructor function
	public function __construct() {
		global $cfg_database, $cfg_host, $cfg_user, $cfg_pass, $cfg_port, $cfg_type;
		
		if ( empty( $cfg_database ) && empty( $cfg_host ) ) {
				$dns = $cfg_type;
				// Get the driver that is to be used
				$split_dns = explode( ':', $dns );
				$driver = $split_dns[0];
			} else {
				// Build the DNS string needed
				if ( $cfg_type == 'mysqli' ) {
					$cfg_type = 'mysql';
				}
				$driver = $cfg_type;
				$dns = sprintf( '%1$s:host=%2$s;dbname=%3$s', $cfg_type, $cfg_host, $cfg_database );
				if ( !empty( $cfg_port ) ) {
					$dns .= ';port='.$cfg_port;
				}				
			}
			/**
			 * Check the needed PDO driver is there
			 */
			if ( !in_array( $driver, $this->getAvailableDrivers() ) ) {
				throw new SQL_InvalidDriver( 'PDO driver "'.$driver.'" is not available, ensure it is installed', 20 );
			}
			try {
				if ( empty( $driver_options ) || !is_array( $driver_options ) ) {
					$driver_options = array(
											PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ,
											);
				}
				if ( $driver == 'mysql' ) {
					$driver_options[ PDO::MYSQL_ATTR_USE_BUFFERED_QUERY ] = true;
				}
				parent::__construct( $dns, $cfg_user, $cfg_pass, $driver_options );
			} catch ( PDOexception $e ) {
				throw new SQL_UnableToConnect( $e->getMessage(), 21 );
			}
	}
	// empty destructor function
	public function __destruct() {
		
	}
	
	public function get_db_prefix() 
	{
		global $cfg_prefix;
		if ( is_null( $this->db_prefix ) ) 
		{
			// Get prefix from config
			$this->set_prefix($cfg_prefix);
		}
		return $this->db_prefix;
	}
	public function set_prefix( $prefix ) 
	{
		$this->db_prefix = $prefix;
	}
	
	public function check_name( $name ) 
	{
			if ( preg_match( '#[A-Z][A-Z0-9_\-]+#i', $name ) && trim( $name ) == $name ) {
				return true;
			} else {
				return false;
			}
	}
	
	public function query( $statement, $arg2='', $arg3='', $arg4='' ) 
	{	
			// Replace {SQL_PREFIX} with the table prefix
			$statement = str_replace( '{SQL_PREFIX}', $this->get_db_prefix(), $statement );
			try {
				$result = parent::query( $statement, $arg2, $arg3, $arg4 );
				return $result;
			} catch ( PDOException $e ) {
				throw new SQL_QueryFailed( $e->getMessage(), 22 );
			}
	}
	public function prepare( $statement, $driver_opts=array() ) 
	{
			$statement = str_replace( '{SQL_PREFIX}', $this->get_db_prefix(), $statement );
			return parent::prepare( $statement, $driver_opts );
	}
	public function num_rows( $result ) 
	{
			return $result->rowCount();
	}
	public function insert_id() 
	{
			return $this->lastInsertID();
	}
	public function insert( $table, $entries, $quote_ident=self::_QUOTE_BOTH ) 
	{
			$table = $this->get_db_prefix().$table;
			if ( $this->check_name( $table ) ) {
				if ( $quote_ident & self::_QUOTE_TABLE ) {
					$table = '`'.$table.'`';
				}
				$query_parts = array();		
				foreach( $entries as $col=>$val ) {
					if ( !$this->check_name( $col ) ) {
						// Column has invalid name
						throw new SQL_InvalidName( sprintf( $this->invalid_format, 'column', $col ), 22 );
					} else if ( $quote_ident & self::_QUOTE_COL ) {
						$query_parts['col'][] = '`'.$col.'`, ';
					} else {
						$query_parts['col'][] = $col.', ';
					}
					$query_parts['val'][] = '?, ';
				}				
				// Create the column and value strings
				$query_parts['col'] = trim( implode( '', $query_parts['col'] ), ', ' );
				$query_parts['val'] = trim( implode( '', $query_parts['val'] ), ', ' );				
				$statement = 'INSERT INTO '.$table.' ( '.$query_parts['col'].' ) VALUES ( '.$query_parts['val'].' )';				
				// Prepare and execute query
				try {
					$pdo_st = parent::prepare( $statement );
					$pdo_st->execute( array_values( $entries ) );
					return $pdo_st;
				} catch ( PDOException $e ) {
					//throw new SQL_QueryFailed( $e->getMessage(), 22 );
				}
			} else {
			//	throw new SQL_InvalidName( sprintf( $this->invalid_format, 'table', $table ), 23 );
			}
	}
	
	public function update( $table, $entries, $where=array(), $quote_ident=self::_QUOTE_BOTH ) {
			$table = $this->get_db_prefix().$table;
			if ( $this->check_name( $table ) ) {
				if ( $quote_ident & self::_QUOTE_TABLE ) {
					$table = '`'.$table.'`';
				}
				$sql = 'UPDATE '.$table.' SET ';
				// Create the middle section of the query
				$middle_sql = '';
				foreach( $entries as $key=>$val ) {
					if ( !$this->check_name( $key ) ) {
						// Column has invalid name
						throw new SQL_InvalidName( sprintf( $this->invalid_format, 'column', $key ), 23 );
					} else if ( $quote_ident & self::_QUOTE_COL ) {
						$key = '`'.$key.'`';
					}
					$middle_sql .= $key.' = ?, ';
				}
				$sql .= trim( $middle_sql, ', ' );
				if ( is_array( $where ) && !empty( $where ) ) {
					// Add where onto the query (Only allows for equals so far)
					$where_sql = '';
					foreach( $where as $key=>$val ) {
						if ( !$this->check_name( $key ) ) {
							// Column has invalid name
							throw new SQL_InvalidName( sprintf( $this->invalid_format, 'column', $key ), 23 );
						} else if ( $quote_ident & self::_QUOTE_COL ) {
							$key = '`'.$key.'`';
						}
						$where_sql .= ' AND '.$key.' = ? ';
					}
					$sql .= ' WHERE '.trim( $where_sql, 'AND ' );
				}
				// Prepare and execute query
				try {
					$pdo_st = parent::prepare( $sql );
					$pdo_st->execute( array_merge( array_values($entries), array_values($where) ) );
					return $pdo_st;
				} catch ( PDOException $e ) {
				//	throw new SQL_QueryFailed( $e->getMessage(), 22 );
				}
			} else {
			//	throw new SQL_InvalidName( sprintf( $this->invalid_format, 'table', $table ), 23 );
			}
	}
	public function select( $table, $where=array(), $cols=array(), $quote_ident=self::_QUOTE_BOTH ) {
			if ( !is_array( $where ) ) {
				$where = array();
			}
			if ( !is_array( $cols ) ) {
				$cols = array();
			}
			$table = $this->get_db_prefix().$table;
			if ( $this->check_name( $table ) ) {
				if ( $quote_ident & self::_QUOTE_TABLE ) {
					$table = '`'.$table.'`';
				}
				if ( (empty( $cols ) || !is_array( $cols )) && (empty( $where ) || !is_array( $where )) ) {
					// Run a straight select all on the provided table
					try {
						$pdo_st = parent::prepare( 'SELECT * FROM '.$table );
						$pdo_st->execute();
						return $pdo_st;
					} catch ( PDOException $e ) {
					//	throw new SQL_QueryFailed( $e->getMessage(), 22 );
					}
				} else {
					/**
					 * Construct the correct query string needed for use with prepared
					 * queries. Depending on the $quote_ident, the column names may be
					 * quoted correctly.
					 */
					$sql = 'SELECT ';
					if ( is_array( $cols ) && !empty( $cols ) ) {
						// Add the columns onto the query
						foreach( $cols as $key=>$column ) {
							if ( is_array( $column ) ) {
								trigger_error( 'Sql::select() invalid column value type (array)', E_USER_WARNING );
								unset( $cols[ $key ] );
							} else if ( !$this->check_name( $column ) ) {
								// Column has invalid name
							//	throw new SQL_InvalidName( sprintf( $this->invalid_format, 'column', $column ), 23 );							
							} else if ( $quote_ident & self::_QUOTE_COL ) {
								$cols[ $key ] = '`'.$column.'`';
							}
						}
						$sql .= trim( implode( ',', $cols ), ', ' );
					} else {
						$sql .= '*';
					}
					$sql .= ' FROM '.$table; # Add the table on
					if ( is_array( $where ) && !empty( $where ) ) {
						// Add Where on
						$where_sql = '';
						foreach( $where as $key=>$val ) {
							if ( is_array( $val ) ) {
								trigger_error( 'Sql::select() invalid where value type (array) for key "'.$key.'"', E_USER_WARNING );
								continue;
							} else if ( !$this->check_name( $key ) ) {
								// Column has invalid name
								throw new SQL_InvalidName( sprintf( $this->invalid_format, 'column', $key ), 23 );
							} else if ( $quote_ident & self::_QUOTE_COL ) {
								$key = '`'.$key.'`';
							}							
							$where_sql .= ' AND '.$key.' = ?';
						}
						$sql .= ' WHERE '.trim( $where_sql, 'AND ' );
					}
					// Prepare and execute query
					try {
						$pdo_st = parent::prepare( $sql );
						$pdo_st->execute( array_values( $where ) );
						return $pdo_st;
					} catch ( PDOException $e ) {
					//	throw new SQL_QueryFailed( $e->getMessage(), 22 );
					}
				}	
			} else {
			//	throw new SQL_InvalidName( sprintf( $this->invalid_format, 'table', $table ), 23 );
			}				
	}	
	public function delete( $table, $where, $quote_ident=self::_QUOTE_BOTH ) {
			$table = $this->get_db_prefix().$table;
			if ( !is_array( $where ) || empty( $where ) ) {
				throw new SQL_QueryFailed( 'second argument must be an array' );
			} else if ( $this->check_name( $table ) ) {
				if ( $quote_ident & self::_QUOTE_TABLE ) {
					$table = '`'.$table.'`';
				}
				$sql = 'DELETE FROM '.$table;
				$where_sql = '';
				foreach( $where as $key=>$val ) {
					if ( is_array( $val ) ) {
						trigger_error( 'Sql::delete() invalid where value type (array) for key "'.$key.'"', E_USER_WARNING );
						continue;
					} else if ( !$this->check_name( $key ) ) {
						// Column has invalid name
						throw new SQL_InvalidName( sprintf( $this->invalid_format, 'column', $key ), 23 );
					} else if ( $quote_ident & self::_QUOTE_COL ) {
						$key = '`'.$key.'`';
					}							
					$where_sql .= ' AND '.$key.' = ?';
				}
				$sql .= ' WHERE '.trim( $where_sql, 'AND ' );
				// Prepare and execute query
				try {
					$pdo_st = parent::prepare( $sql );
					$pdo_st->execute( array_values( $where ) );
					return $pdo_st;
				} catch ( PDOException $e ) {
				//	throw new SQL_QueryFailed( $e->getMessage(), 22 );
				}
			} else {
			//	throw new SQL_InvalidName( sprintf( $this->invalid_format, 'table', $table ), 23 );
			}
	}
	public function split_sql_file( $file, $delimiter=';', $run_queries=true ) {
			if ( !is_file( $file ) || !is_readable( $file ) ) {
				throw new Sql_InvalidFile( $file.' does not exist or is not readable' );
			}
			// Remove comments from file
			$file_contents = file_get_contents( $file );
			$this->remove_remarks( $file_contents );
			/**
			 * Get string into one big line, splitting on the delimiter
			 * and then trimming off any white space
			 */
			$sql = str_replace( "\r" , '', $file_contents );
			$data = preg_split( '/' . preg_quote( $delimiter, '/' ) . '$/m', $file_contents );
			$data = array_map( 'trim' , $data) ;
			// The empty case
			$end_data = end( $data );
			if ( empty( $end_data ) ) {
				unset( $data[ key( $data ) ] );
			}
			if ( $run_queries == true ) {
				foreach( $data as $key=>$query ) {
					if ( !trim( $query ) ) {
						unset( $data[ $key ] );
					} else {
						$this->query( $query );
					}
				}
			}
			return $data;
	}
}

Может еще ко мне кто придирется, давненько уже ни с кем не ссорился :D
 
dumber, ты, конечно, не обижайся... Но чего-то ты намудрил :)

PHP:
public function __construct() {
        global $cfg_database, $cfg_host, $cfg_user, $cfg_pass, $cfg_port, $cfg_type;
Ничего не смущает, не? Как-то globals не смотрятся :)

PHP:
public function set_prefix( $prefix ) 
    {
        $this->db_prefix = $prefix;
    }
Что мешает magic-функции использовать (если так хочется извне переопределять)?
PHP:
 $db -> __set('db_prefix', $prefix);

Мягко говоря, непонятно введение в условия констант, которые заведомо возвратят true
PHP:
if ( $quote_ident & self::_QUOTE_TABLE ) {

Мутновато, все-таки...
 
dumber, ты, конечно, не обижайся... Но чего-то ты намудрил :)

PHP:
public function __construct() {
        global $cfg_database, $cfg_host, $cfg_user, $cfg_pass, $cfg_port, $cfg_type;
Ничего не смущает, не? Как-то globals не смотрятся :)

ГЫ, класс то взял с проекта, доп функции я убрал а глобалки не заметил, оставил :) Они там не нужны, в оригинале в качестве параметров construct все передавалось :)

PHP:
public function set_prefix( $prefix ) 
    {
        $this->db_prefix = $prefix;
    }
Что мешает magic-функции использовать (если так хочется извне переопределять)?
PHP:
 $db -> __set('db_prefix', $prefix);

Ну мне так больше нравица :)

Мягко говоря, непонятно введение в условия констант, которые заведомо возвратят true
PHP:
if ( $quote_ident & self::_QUOTE_TABLE ) {

а тут quote_ident может быть и константой QUOTE_NONE которая равна нулю, тобишь false а значит не нужно нам кавычки ставить :)

Мутновато, все-таки...
а если все четко и ясно то неинтересно ;)
ну и я никогда не пишу коды для других, цели мои использование тоже мое, а делюсь так просто от нечего делать :)
 
Simpson, на той же википедии ясно написано "Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контролера ), изменяя свое состояние." так что не надо :smmne:

А если говорить про GoF, то открой 19ю (это ещё введение, кстати :D) страницу (ну в той версии книги, что у меня)
MVC consists of three kinds of objects. The Model is the application object, the View is its screen
presentation
, and the Controller defines the way the user interface reacts to user input. Before MVC, user
interface designs tended to lump these objects together. MVC decouples them to increase flexibility and
reuse.
MVC decouples views and models by establishing a subscribe/notify protocol between them. A view must
ensure that its appearance reflects the state of the model. Whenever the model's data changes, the model
notifies views that depend on it.
In response, each view gets an opportunity to update itself. This approach
lets you attach multiple views to a model to provide different presentations. You can also create new views
for a model without rewriting it.

The following diagram shows a model and three views. (We've left out the controllers for simplicity.) The
model contains some data values, and the views defining a spreadsheet, histogram, and pie chart display
these data in various ways. The model communicates with its views when its values change, and the views
communicate with the model to access these values.
последний абзац специально выделил :confused:

Для просмотра ссылки Войди или Зарегистрируйся

ну и себя процитирую:
Любая работа с данными (вырезано для упрощения восприятия предложения целиком) есть бизнес-логика приложения. По GoF она относится к модели в паттерне MVC, адептом которого я и являюсь

Работа с любыми данными возлагается на модель. И это в понимании широких кругов разработчиков есть именно бизнес-логика приложений. Не важно откуда данные берутся (база, файловая система или что ещё), важно отделить работу с ними от всей остальной части приложения.

dumber, зачётно, молодец. Сам всё никак не соберусь написать апдейт, делит и селект методы для своего класса. Было бы полезно, но лень :) у меня в моделях хранятся в константах шаблоны запросов к базе :ah:
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху