├── example.py ├── README.md ├── Mysql.class.php └── libmysql.py /example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | """ table structure; 5 | CREATE TABLE `users` ( 6 | `id` int(11) NOT NULL AUTO_INCREMENT, 7 | `email` varchar(255) COLLATE utf8_bin NOT NULL, 8 | `password` varchar(255) COLLATE utf8_bin NOT NULL, 9 | PRIMARY KEY (`id`) 10 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 11 | """ 12 | 13 | from libmysql import MYSQL 14 | 15 | # msyql dababase connection info 16 | dbconn = MYSQL( 17 | dbhost = 'localhost', 18 | dbuser = 'root', 19 | dbpwd = '', 20 | dbname = 'wyproxy', 21 | dbcharset = 'utf8') 22 | 23 | # insert data, 插入数据 24 | user = {'email': 'ringzero@0x557.org', 'password': '123123'} 25 | dbconn.insert(table='users', data=user) 26 | 27 | # change user dict, 修改用户信息提交 28 | user['email'] = 'ringzero@wooyun.org' 29 | user['password'] = '123456' 30 | dbconn.insert(table='users', data=user) 31 | 32 | # update 更新用户信息 33 | user = {'email': 'newringzero@0x557.org', 'password': '888888'} 34 | cond = {'email': 'ringzero@0x557.org'} 35 | rows = dbconn.update(table='users', data=user, condition=cond) 36 | print('update {} records success..'.format(rows)) 37 | 38 | # delete data, 删除数据, limit参数为删除少条 39 | cond = {'email': 'ringzero@0x557.org'} 40 | rows = dbconn.delete(table='users', condition=cond, limit='1') 41 | print('deleted {} records success..'.format(rows)) 42 | 43 | # 统计数据库记录条数 44 | cond = {'email': 'ringzero@wooyun.org'} 45 | cnt = dbconn.count( 46 | table='users', 47 | condition=cond) 48 | print(cnt) 49 | 50 | # select 查询信息 51 | fields = ('id', 'email') 52 | cond = {'email': 'ringzero@wooyun.org'} 53 | rows = dbconn.fetch_rows( 54 | table='users', 55 | fields=fields, 56 | condition=cond, 57 | order='id asc', 58 | limit='0,5') 59 | 60 | for row in rows: 61 | print(row) 62 | 63 | # 不指定 fields 字段, 将返回所有*字段, 64 | # 不指定 order, 将不进行排序 65 | # 不指定 limit, 将返回所有记录 66 | 67 | rows = dbconn.fetch_rows( 68 | table='users', 69 | condition=cond, 70 | limit='0,5') 71 | for row in rows: 72 | print(row) 73 | 74 | # query 执行自定义SQL语句 75 | sql = 'select * from users limit 0, 5' 76 | rows = dbconn.query(sql) 77 | for row in rows: 78 | print(row) 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Friendly pymysql CURD Class 2 | Based on Mysql.class.php 3 | 4 | [wyproxy](https://github.com/ring04h/wyproxy) 的web控制台, flask + pymysql 5 | 6 | 不想使用sqlalchemy, 又没有好用的轮子类, 就自己造一个了 7 | 8 | ## EXAMPLE 使用帮助 9 | ### 防止SQL注入建议 10 | 一定要记得针对来自客户端的变量进行安全转义 11 | ```python 12 | from pymysql import escape_string 13 | id = request.args.get('id') 14 | id = escape_string(id) 15 | ``` 16 | 17 | ### 使用参数绑定的方式来防止SQL注入 18 | ```python 19 | def insert(self, table, data): 20 | """mysql insert() function""" 21 | with self.connection.cursor() as cursor: 22 | params = self.join_field_value(data); 23 | sql = "INSERT INTO {table} SET {params}".format(table=table, params=params) 24 | cursor.execute(sql, tuple(data.values())) 25 | self.connection.commit() 26 | 27 | def join_field_value(self, data, glue = ', '): 28 | sql = comma = '' 29 | for key, value in data.items(): 30 | sql += "{}`{}` = %s".format(comma, key) 31 | comma = glue 32 | return sql 33 | ``` 34 | 35 | ### 引入Class类 36 | ```python 37 | from libmysql import MYSQL 38 | ``` 39 | 40 | ### 数据库表结构 41 | 42 | ```sql 43 | CREATE TABLE `users` ( 44 | `id` int(11) NOT NULL AUTO_INCREMENT, 45 | `email` varchar(255) COLLATE utf8_bin NOT NULL, 46 | `password` varchar(255) COLLATE utf8_bin NOT NULL, 47 | PRIMARY KEY (`id`) 48 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 49 | ``` 50 | 51 | ### 初始化数据库连接 52 | ```python 53 | # msyql dababase connection info 54 | dbconn = MYSQL( 55 | dbhost = 'localhost', 56 | dbuser = 'root', 57 | dbpwd = '', 58 | dbname = 'wyproxy', 59 | dbcharset = 'utf8') 60 | ``` 61 | 62 | ### 插入数据 63 | ```python 64 | user = {'email': 'ringzero@0x557.org', 'password': '123123'} 65 | dbconn.insert(table='users', data=user) 66 | 67 | # change user dict, 修改用户信息提交 68 | user['email'] = 'ringzero@wooyun.org' 69 | user['password'] = '123456' 70 | dbconn.insert(table='users', data=user) 71 | ``` 72 | 73 | ### update 更新信息 74 | ```python 75 | user = {'email': 'newringzero@0x557.org', 'password': '888888'} 76 | cond = {'email': 'ringzero@0x557.org'} 77 | rows = dbconn.update(table='users', data=user, condition=cond) 78 | print('update {} records success..'.format(rows)) 79 | ``` 80 | 81 | ### delete data, 删除数据, limit参数为删除少条 82 | ```python 83 | cond = {'email': 'ringzero@0x557.org'} 84 | rows = dbconn.delete(table='users', condition=cond, limit='1') 85 | print('deleted {} records success..'.format(rows)) 86 | ``` 87 | 88 | ### select 查询信息 89 | ```python 90 | fields = ('id', 'email') 91 | cond = {'email': 'ringzero@wooyun.org'} 92 | rows = dbconn.fetch_rows( 93 | table='users', 94 | fields=fields, 95 | condition=cond, 96 | order='id asc', 97 | limit='0,5') 98 | 99 | for row in rows: 100 | print(row) 101 | 102 | # 不指定 fields 字段, 将返回所有*字段, 103 | # 不指定 order, 将不进行排序 104 | # 不指定 limit, 将返回所有记录 105 | 106 | rows = dbconn.fetch_rows( 107 | table='users', 108 | condition=cond, 109 | limit='0,5') 110 | for row in rows: 111 | print(row) 112 | ``` 113 | 114 | ### 统计数据库记录条数 115 | 不指定 condition 字段, 将返回数据库的总记录条数 116 | ```python 117 | cond = {'email': 'ringzero@wooyun.org'} 118 | cnt = dbconn.count( 119 | table='users', 120 | condition=cond) 121 | print(cnt) 122 | ``` 123 | 124 | ### query 执行自定义SQL语句 125 | ```python 126 | sql = 'select * from users limit 0, 5' 127 | rows = dbconn.query(sql) 128 | for row in rows: 129 | print(row) 130 | ``` -------------------------------------------------------------------------------- /Mysql.class.php: -------------------------------------------------------------------------------- 1 | 'change the title', 13 | 'detail' => 'change the detail', 14 | 'begin_time' => '1'); 15 | 16 | $condition = array('id' => '71', 'title' => 'dsad'); 17 | $db->update('news', $data, $condition); 18 | 19 | 20 | // insert 21 | $data = array( 22 | 'id' => NULL, 23 | 'title' => '74', 24 | 'detail' => 'dsad', 25 | 'begin_time' => '0'); 26 | $db->insert('news', $data); 27 | 28 | // delete 29 | $condition = array( 30 | 'id' => '74', 31 | 'title' => 'dsad'); 32 | $db->delete('news', $condition); 33 | 34 | // query 35 | $query = $db->query('select * from u_members where uid < 100'); 36 | while ($members = $db->fetch_array($query)) { 37 | print_r($members); 38 | } 39 | */ 40 | 41 | class db_mysql { 42 | 43 | private $dbhost; 44 | private $dbuser; 45 | private $dbpwd; 46 | private $dbname; 47 | private $dbcharset; 48 | 49 | function __construct($dbhost = DB_HOST, $dbuser = DB_USER, $dbpw = DB_PASSWORD, $dbcharset = DB_CHARSET, $dbname = DB_NAME){ 50 | $this->dbhost = $dbhost; 51 | $this->dbuser = $dbuser; 52 | $this->dbpw = $dbpw; 53 | $this->dbcharset = $dbcharset; 54 | $this->dbname = $dbname; 55 | $this->connect(); 56 | } 57 | 58 | function connect(){ 59 | $link = @mysql_connect ( $this->dbhost, $this->dbuser, $this->dbpw ) or $this->halt( mysql_error() ); 60 | mysql_select_db( $this->dbname, $link ) or $this->halt ( mysql_error() ); 61 | mysql_query("SET NAMES '$this->dbcharset'"); 62 | } 63 | 64 | function delete($table, $condition, $limit = 0) { 65 | if (empty ( $condition )) { 66 | $where = '1'; 67 | } elseif (is_array ( $condition )) { 68 | $where = $this->implode_field_value ( $condition, ' AND ' ); 69 | } else { 70 | $where = $condition; 71 | } 72 | $sql = "DELETE FROM " . $table . " WHERE $where " . ($limit ? "LIMIT $limit" : ''); 73 | return $this->query ( $sql ); 74 | } 75 | 76 | function insert($table, $data, $return_insert_id = false) { 77 | $sql = $this->implode_field_value ( $data ); 78 | $return = $this->query ( "INSERT INTO $table SET $sql" ); 79 | return $return_insert_id ? $this->insert_id () : $return; 80 | } 81 | 82 | function update($table, $data, $condition) { 83 | $sql = $this->implode_field_value ( $data ); 84 | $where = ''; 85 | if (empty ( $condition )) { 86 | $where = '1'; 87 | } elseif (is_array ( $condition )) { 88 | $where = $this->implode_field_value ( $condition, ' AND ' ); 89 | } else { 90 | $where = $condition; 91 | } 92 | $res = $this->query ( "UPDATE $table SET $sql WHERE $where" ); 93 | return $res; 94 | } 95 | 96 | function fetch_array($query, $result_type = MYSQL_ASSOC) { 97 | return mysql_fetch_array ( $query, $result_type ); 98 | } 99 | 100 | function fetch_first($sql) { 101 | return $this->fetch_array ( $this->query ( $sql ) ); 102 | } 103 | 104 | function result_first($sql) { 105 | return $this->result ( $this->query ( $sql ), 0 ); 106 | } 107 | 108 | function affected_rows() { 109 | return mysql_affected_rows(); 110 | } 111 | 112 | function result($query, $row = 0) { 113 | $query = @mysql_result ( $query, $row ); 114 | return $query; 115 | } 116 | 117 | function num_rows($query) { 118 | $query = mysql_num_rows ( $query ); 119 | return $query; 120 | } 121 | 122 | function num_fields($query) { 123 | return mysql_num_fields ( $query ); 124 | } 125 | 126 | function free_result($query) { 127 | return mysql_free_result ( $query ); 128 | } 129 | 130 | function fetch_row($query) { 131 | $query = mysql_fetch_row ( $query ); 132 | return $query; 133 | } 134 | 135 | function fetch_fields($query) { 136 | return mysql_fetch_field ( $query ); 137 | } 138 | 139 | function version() { 140 | return mysql_get_server_info(); 141 | } 142 | 143 | function close() { 144 | return mysql_close(); 145 | } 146 | 147 | function implode_field_value($array, $glue = ',') { 148 | $sql = $comma = ''; 149 | foreach ($array as $k => $v) { 150 | $sql .= $comma."`$k`='$v'"; 151 | $comma = $glue; 152 | } 153 | return $sql; 154 | } 155 | 156 | public function halt($message = '', $sql = '') { 157 | echo "Error Page

ERROR INFO : $sql

$message

"; 158 | exit (); 159 | } 160 | 161 | function query($sql, $type = '') { 162 | if(!($query = mysql_query($sql))) $this->halt ( mysql_error(), $sql ); 163 | return $query; 164 | } 165 | } 166 | ?> -------------------------------------------------------------------------------- /libmysql.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | """ 4 | author: ringzero@0x557.org 5 | home: http://github.com/ring04h/fpymysql 6 | desc: A Friendly pymysql CURD Class 7 | 8 | https://dev.mysql.com/doc/connector-python/en/connector-python-reference.html 9 | 10 | SQL Injection Warning: pymysql.escape_string(value) 11 | 12 | """ 13 | 14 | from pymysql import (connect, cursors, err, escape_sequence) 15 | 16 | 17 | def connect_db(mysqldb_conn): 18 | # msyql dababase connection info 19 | dbconn = MYSQL( 20 | dbhost=mysqldb_conn.get('host'), 21 | dbport=mysqldb_conn.get('port'), 22 | dbuser=mysqldb_conn.get('user'), 23 | dbpwd=mysqldb_conn.get('password'), 24 | dbname=mysqldb_conn.get('db'), 25 | dbcharset=mysqldb_conn.get('charset')) 26 | return dbconn 27 | 28 | 29 | def connect_ssdc(mysqldb_conn): 30 | """Connect to the database return SSDictCursor dbsession""" 31 | connection = connect( 32 | host=mysqldb_conn.get('host'), 33 | port=int(mysqldb_conn.get('port')) or 3306, 34 | user=mysqldb_conn.get('user'), 35 | password=mysqldb_conn.get('password'), 36 | db=mysqldb_conn.get('db'), 37 | charset=mysqldb_conn.get('charset'), 38 | cursorclass=cursors.SSDictCursor) 39 | return connection 40 | 41 | 42 | class MYSQL: 43 | """A Friendly pymysql Class, Provide CRUD functionality""" 44 | 45 | def __init__(self, dbhost, dbuser, dbpwd, dbname, dbcharset='utf-8', dbport=3306): 46 | self.dbhost = dbhost 47 | self.dbport = int(dbport) 48 | self.dbuser = dbuser 49 | self.dbpwd = dbpwd 50 | self.dbname = dbname 51 | self.dbcharset = dbcharset 52 | self.connection = self.session() 53 | 54 | def session(self): 55 | """Connect to the database return dbsession""" 56 | connection = connect( 57 | host=self.dbhost, 58 | port=self.dbport, 59 | user=self.dbuser, 60 | password=self.dbpwd, 61 | db=self.dbname, 62 | charset=self.dbcharset, 63 | cursorclass=cursors.DictCursor) 64 | return connection 65 | 66 | def insert(self, table, data): 67 | """mysql insert() function""" 68 | 69 | with self.connection.cursor() as cursor: 70 | 71 | params = self.join_field_value(data) 72 | 73 | sql = "INSERT IGNORE INTO {table} SET {params}".format( 74 | table=table, params=params) 75 | 76 | cursor.execute(sql, tuple(data.values())) 77 | last_id = self.connection.insert_id() 78 | 79 | self.connection.commit() 80 | return last_id 81 | 82 | def bulk_insert(self, table, data): 83 | 84 | assert isinstance(data, list) and data != [], "data_format_error" 85 | 86 | with self.connection.cursor() as cursor: 87 | 88 | params = [] 89 | for param in data: 90 | params.append(escape_sequence(param.values(), 'utf-8')) 91 | 92 | values = ', '.join(params) 93 | fields = ', '.join('`{}`'.format(x) for x in param.keys()) 94 | 95 | sql = u"INSERT IGNORE INTO {table} ({fields}) VALUES {values}".format( 96 | fields=fields, table=table, values=values) 97 | 98 | cursor.execute(sql) 99 | last_id = self.connection.insert_id() 100 | 101 | self.connection.commit() 102 | return last_id 103 | 104 | def delete(self, table, condition=None, limit=None): 105 | """ 106 | mysql delete() function 107 | sql.PreparedStatement method 108 | """ 109 | with self.connection.cursor() as cursor: 110 | 111 | prepared = [] 112 | 113 | if not condition: 114 | where = '1' 115 | elif isinstance(condition, dict): 116 | where = self.join_field_value(condition, ' AND ') 117 | prepared.extend(condition.values()) 118 | else: 119 | where = condition 120 | 121 | limits = "LIMIT {limit}".format(limit=limit) if limit else "" 122 | 123 | sql = "DELETE FROM {table} WHERE {where} {limits}".format( 124 | table=table, where=where, limits=limits) 125 | 126 | if not prepared: 127 | result = cursor.execute(sql) 128 | else: 129 | result = cursor.execute(sql, tuple(prepared)) 130 | 131 | self.connection.commit() 132 | return result 133 | 134 | def update(self, table, data, condition=None): 135 | """ 136 | mysql update() function 137 | Use sql.PreparedStatement method 138 | """ 139 | with self.connection.cursor() as cursor: 140 | 141 | prepared = [] 142 | params = self.join_field_value(data) 143 | prepared.extend(data.values()) 144 | 145 | if not condition: 146 | where = '1' 147 | elif isinstance(condition, dict): 148 | where = self.join_field_value(condition, ' AND ') 149 | prepared.extend(condition.values()) 150 | else: 151 | where = condition 152 | 153 | sql = "UPDATE IGNORE {table} SET {params} WHERE {where}".format( 154 | table=table, params=params, where=where) 155 | 156 | # check PreparedStatement 157 | if not prepared: 158 | result = cursor.execute(sql) 159 | else: 160 | result = cursor.execute(sql, tuple(prepared)) 161 | 162 | self.connection.commit() 163 | return result 164 | 165 | def count(self, table, condition=None): 166 | """ 167 | count database record 168 | Use sql.PreparedStatement method 169 | """ 170 | with self.connection.cursor() as cursor: 171 | 172 | prepared = [] 173 | 174 | if not condition: 175 | where = '1' 176 | elif isinstance(condition, dict): 177 | where = self.join_field_value(condition, ' AND ') 178 | prepared.extend(condition.values()) 179 | else: 180 | where = condition 181 | 182 | sql = "SELECT COUNT(*) as cnt FROM {table} WHERE {where}".format( 183 | table=table, where=where) 184 | 185 | if not prepared: 186 | cursor.execute(sql) 187 | else: 188 | cursor.execute(sql, tuple(prepared)) 189 | 190 | self.connection.commit() 191 | return cursor.fetchone().get('cnt') 192 | 193 | def fetch_rows(self, table, fields=None, condition=None, order=None, limit=None, fetchone=False): 194 | """ 195 | mysql select() function 196 | Use sql.PreparedStatement method 197 | """ 198 | with self.connection.cursor() as cursor: 199 | 200 | prepared = [] 201 | 202 | if not fields: 203 | fields = '*' 204 | elif isinstance(fields, tuple) or isinstance(fields, list): 205 | fields = '`{0}`'.format('`, `'.join(fields)) 206 | else: 207 | fields = fields 208 | 209 | if not condition: 210 | where = '1' 211 | elif isinstance(condition, dict): 212 | where = self.join_field_value(condition, ' AND ') 213 | prepared.extend(condition.values()) 214 | else: 215 | where = condition 216 | 217 | if not order: 218 | orderby = '' 219 | else: 220 | orderby = 'ORDER BY {order}'.format(order=order) 221 | 222 | limits = "LIMIT {limit}".format(limit=limit) if limit else "" 223 | 224 | sql = "SELECT {fields} FROM {table} WHERE {where} {orderby} {limits}".format( 225 | fields=fields, table=table, where=where, orderby=orderby, limits=limits) 226 | 227 | if not prepared: 228 | cursor.execute(sql) 229 | else: 230 | cursor.execute(sql, tuple(prepared)) 231 | 232 | self.connection.commit() 233 | return cursor.fetchone() if fetchone else cursor.fetchall() 234 | 235 | def query(self, sql, fetchone=False, execute=False): 236 | """execute custom sql query""" 237 | with self.connection.cursor() as cursor: 238 | 239 | cursor.execute(sql) 240 | self.connection.commit() 241 | 242 | if execute: 243 | return 244 | 245 | return cursor.fetchone() if fetchone else cursor.fetchall() 246 | 247 | def join_field_value(self, data, glue=', '): 248 | sql = comma = '' 249 | for key in data.keys(): 250 | sql += "{}`{}` = %s".format(comma, key) 251 | comma = glue 252 | return sql 253 | 254 | def close(self): 255 | if getattr(self, 'connection', 0): 256 | return self.connection.close() 257 | 258 | def __del__(self): 259 | """close mysql database connection""" 260 | self.close() 261 | --------------------------------------------------------------------------------