1: <?php
2:
3: /**
4: * Database wrapper
5: * @package framework
6: * @subpackage db
7: */
8:
9: /**
10: * DB interface for the framework and modules
11: */
12: class Hm_DB {
13:
14: /* DB connection handlers */
15: static public $dbh = [];
16:
17: /* required DB configuration params */
18: static private $required_config = ['db_user', 'db_pass', 'db_name', 'db_host', 'db_driver'];
19:
20: /* DB config */
21: static private $config;
22:
23: /**
24: * Load DB configuration from the site config
25: * @param object $site_config site config
26: * @return void
27: */
28: static private function parse_config($site_config) {
29: self::$config = [
30: 'db_driver' => $site_config->get('db_driver', false),
31: 'db_host' => $site_config->get('db_host', false),
32: 'db_name' => $site_config->get('db_name', false),
33: 'db_user' => $site_config->get('db_user', false),
34: 'db_pass' => $site_config->get('db_pass', false),
35: 'db_socket' => $site_config->get('db_socket', false),
36: 'db_conn_type' => $site_config->get('db_connection_type', 'host'),
37: 'db_port' => $site_config->get('db_port', false),
38: ];
39:
40: foreach (self::$required_config as $v) {
41: if (!self::$config[$v]) {
42: Hm_Debug::add(sprintf('Missing configuration setting for %s', $v));
43: }
44: }
45: }
46:
47: /**
48: * Return a unique key for a DB connection
49: * @return string md5 of the DB settings
50: */
51: static private function db_key() {
52: return md5(self::$config['db_driver'].
53: self::$config['db_host'].
54: self::$config['db_port'].
55: self::$config['db_name'].
56: self::$config['db_user'].
57: self::$config['db_pass'].
58: self::$config['db_conn_type'].
59: self::$config['db_socket']
60: );
61: }
62:
63: /**
64: * Build a DSN to connect to the db with
65: * @return string
66: */
67: static public function build_dsn() {
68: if (self::$config['db_driver'] == 'sqlite') {
69: return sprintf('%s:%s', self::$config['db_driver'], self::$config['db_socket']);
70: }
71: if (self::$config['db_conn_type'] == 'socket') {
72: return sprintf('%s:unix_socket=%s;dbname=%s', self::$config['db_driver'], self::$config['db_socket'], self::$config['db_name']);
73: } else {
74: if (self::$config['db_port']) {
75: return sprintf('%s:host=%s;port=%s;dbname=%s', self::$config['db_driver'], self::$config['db_host'], self::$config['db_port'], self::$config['db_name']);
76: } else {
77: return sprintf('%s:host=%s;dbname=%s', self::$config['db_driver'], self::$config['db_host'], self::$config['db_name']);
78: }
79: }
80: }
81:
82: /**
83: * @param object|false $dbh PDO connection object
84: * @param string $sql sql with placeholders to execute
85: * @param array $args values to insert into the sql
86: * @param bool $type optional type of sql query
87: * @param bool $all optional flag to return multiple rows
88: * @return boolean|integer|array
89: */
90: static public function execute($dbh, $sql, $args, $type = false, $all = false) {
91: if (!$dbh) {
92: return false;
93: }
94: if (!$type) {
95: $type = self::execute_type($sql);
96: }
97: try {
98: $sql = $dbh->prepare($sql);
99: if (!$sql || !$sql->execute($args)) {
100: return false;
101: }
102: if ($type == 'modify' || $type == 'insert') {
103: return $sql->rowCount();
104: }
105: if ($all) {
106: return $sql->fetchAll(PDO::FETCH_ASSOC);
107: }
108: return $sql->fetch(PDO::FETCH_ASSOC);
109: } catch (PDOException $oops) {
110: Hm_Msgs::add('Database error. Please try again.', 'danger');
111: Hm_Debug::add($oops->getMessage());
112: return false;
113: }
114: }
115:
116: /**
117: * @param string $sql query string
118: * @return string
119: */
120: static private function execute_type($sql) {
121: switch(mb_substr($sql, 0, 1)) {
122: case 'd':
123: case 'u':
124: case 'i':
125: return 'modify';
126: case 's':
127: default:
128: return 'select';
129: }
130: }
131:
132: /**
133: * Connect to a DB server
134: * @param object $site_config site settings
135: * @return object|false database connection on success
136: */
137: static public function connect($site_config) {
138: self::parse_config($site_config);
139: $key = self::db_key();
140:
141: if (!empty(self::$dbh[$key])) {
142: return self::$dbh[$key];
143: }
144: $dsn = self::build_dsn();
145: try {
146: self::$dbh[$key] = new PDO($dsn, self::$config['db_user'], self::$config['db_pass']);
147: self::$dbh[$key]->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
148: self::$dbh[$key]->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
149: Hm_Debug::add(sprintf('Connecting to dsn: %s', $dsn), "info");
150: return self::$dbh[$key];
151: } catch (Exception $oops) {
152: Hm_Debug::add($oops->getMessage());
153: Hm_Msgs::add('Unable to connect to the database. Please check your configuration settings and try again.', 'danger');
154: self::$dbh[$key] = false;
155: return false;
156: }
157: }
158: }
159: