PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/include/database/MysqliManager.php

https://gitlab.com/tjaafar/SuiteCRM
PHP | 379 lines | 176 code | 43 blank | 160 comment | 40 complexity | c66e5747b1e43ed32e84904753b33871 MD5 | raw file
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3. /*********************************************************************************
  4. * SugarCRM Community Edition is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
  6. * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
  7. * Copyright (C) 2011 - 2014 Salesagility Ltd.
  8. *
  9. * This program is free software; you can redistribute it and/or modify it under
  10. * the terms of the GNU Affero General Public License version 3 as published by the
  11. * Free Software Foundation with the addition of the following permission added
  12. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  13. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  14. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  15. *
  16. * This program is distributed in the hope that it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  18. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  19. * details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License along with
  22. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  23. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  24. * 02110-1301 USA.
  25. *
  26. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  27. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  28. *
  29. * The interactive user interfaces in modified source and object code versions
  30. * of this program must display Appropriate Legal Notices, as required under
  31. * Section 5 of the GNU Affero General Public License version 3.
  32. *
  33. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  34. * these Appropriate Legal Notices must retain the display of the "Powered by
  35. * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
  36. * reasonably feasible for technical reasons, the Appropriate Legal Notices must
  37. * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
  38. ********************************************************************************/
  39. /*********************************************************************************
  40. * Description: This file handles the Data base functionality for the application.
  41. * It acts as the DB abstraction layer for the application. It depends on helper classes
  42. * which generate the necessary SQL. This sql is then passed to PEAR DB classes.
  43. * The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php.
  44. *
  45. * All the functions in this class will work with any bean which implements the meta interface.
  46. * The passed bean is passed to helper class which uses these functions to generate correct sql.
  47. *
  48. * The meta interface has the following functions:
  49. * getTableName() Returns table name of the object.
  50. * getFieldDefinitions() Returns a collection of field definitions in order.
  51. * getFieldDefintion(name) Return field definition for the field.
  52. * getFieldValue(name) Returns the value of the field identified by name.
  53. * If the field is not set, the function will return boolean FALSE.
  54. * getPrimaryFieldDefinition() Returns the field definition for primary key
  55. *
  56. * The field definition is an array with the following keys:
  57. *
  58. * name This represents name of the field. This is a required field.
  59. * type This represents type of the field. This is a required field and valid values are:
  60. * � int
  61. * � long
  62. * � varchar
  63. * � text
  64. * � date
  65. * � datetime
  66. * � double
  67. * � float
  68. * � uint
  69. * � ulong
  70. * � time
  71. * � short
  72. * � enum
  73. * length This is used only when the type is varchar and denotes the length of the string.
  74. * The max value is 255.
  75. * enumvals This is a list of valid values for an enum separated by "|".
  76. * It is used only if the type is �enum�;
  77. * required This field dictates whether it is a required value.
  78. * The default value is �FALSE�.
  79. * isPrimary This field identifies the primary key of the table.
  80. * If none of the fields have this flag set to �TRUE�,
  81. * the first field definition is assume to be the primary key.
  82. * Default value for this field is �FALSE�.
  83. * default This field sets the default value for the field definition.
  84. *
  85. *
  86. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  87. * All Rights Reserved.
  88. * Contributor(s): ______________________________________..
  89. ********************************************************************************/
  90. require_once('include/database/MysqlManager.php');
  91. /**
  92. * MySQL manager implementation for mysqli extension
  93. */
  94. class MysqliManager extends MysqlManager
  95. {
  96. /**
  97. * @see DBManager::$dbType
  98. */
  99. public $dbType = 'mysql';
  100. public $variant = 'mysqli';
  101. public $priority = 10;
  102. public $label = 'LBL_MYSQLI';
  103. /**
  104. * @see DBManager::$backendFunctions
  105. */
  106. protected $backendFunctions = array(
  107. 'free_result' => 'mysqli_free_result',
  108. 'close' => 'mysqli_close',
  109. 'row_count' => 'mysqli_num_rows',
  110. 'affected_row_count' => 'mysqli_affected_rows',
  111. );
  112. /**
  113. * @see MysqlManager::query()
  114. */
  115. public function query($sql, $dieOnError = false, $msg = '', $suppress = false, $keepResult = false)
  116. {
  117. if(is_array($sql)) {
  118. return $this->queryArray($sql, $dieOnError, $msg, $suppress);
  119. }
  120. static $queryMD5 = array();
  121. parent::countQuery($sql);
  122. $GLOBALS['log']->info('Query:' . $sql);
  123. $this->checkConnection();
  124. $this->query_time = microtime(true);
  125. $this->lastsql = $sql;
  126. $result = $suppress?@mysqli_query($this->database,$sql):mysqli_query($this->database,$sql);
  127. $md5 = md5($sql);
  128. if (empty($queryMD5[$md5]))
  129. $queryMD5[$md5] = true;
  130. $this->query_time = microtime(true) - $this->query_time;
  131. $GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
  132. // This is some heavy duty debugging, leave commented out unless you need this:
  133. /*
  134. $bt = debug_backtrace();
  135. for ( $i = count($bt) ; $i-- ; $i > 0 ) {
  136. if ( strpos('MysqliManager.php',$bt[$i]['file']) === false ) {
  137. $line = $bt[$i];
  138. }
  139. }
  140. $GLOBALS['log']->fatal("${line['file']}:${line['line']} ${line['function']} \nQuery: $sql\n");
  141. */
  142. if($keepResult)
  143. $this->lastResult = $result;
  144. $this->checkError($msg.' Query Failed: ' . $sql, $dieOnError);
  145. return $result;
  146. }
  147. /**
  148. * Returns the number of rows affected by the last query
  149. *
  150. * @return int
  151. */
  152. public function getAffectedRowCount($result)
  153. {
  154. return mysqli_affected_rows($this->getDatabase());
  155. }
  156. /**
  157. * Returns the number of rows returned by the result
  158. *
  159. * This function can't be reliably implemented on most DB, do not use it.
  160. * @abstract
  161. * @deprecated
  162. * @param resource $result
  163. * @return int
  164. */
  165. public function getRowCount($result)
  166. {
  167. return mysqli_num_rows($result);
  168. }
  169. /**
  170. * Disconnects from the database
  171. *
  172. * Also handles any cleanup needed
  173. */
  174. public function disconnect()
  175. {
  176. $GLOBALS['log']->debug('Calling MySQLi::disconnect()');
  177. if(!empty($this->database)){
  178. $this->freeResult();
  179. mysqli_close($this->database);
  180. $this->database = null;
  181. }
  182. }
  183. /**
  184. * @see DBManager::freeDbResult()
  185. */
  186. protected function freeDbResult($dbResult)
  187. {
  188. if(!empty($dbResult))
  189. mysqli_free_result($dbResult);
  190. }
  191. /**
  192. * @see DBManager::getFieldsArray()
  193. */
  194. public function getFieldsArray($result, $make_lower_case = false)
  195. {
  196. $field_array = array();
  197. if (!isset($result) || empty($result))
  198. return 0;
  199. $i = 0;
  200. while ($i < mysqli_num_fields($result)) {
  201. $meta = mysqli_fetch_field_direct($result, $i);
  202. if (!$meta)
  203. return 0;
  204. if($make_lower_case == true)
  205. $meta->name = strtolower($meta->name);
  206. $field_array[] = $meta->name;
  207. $i++;
  208. }
  209. return $field_array;
  210. }
  211. /**
  212. * @see DBManager::fetchRow()
  213. */
  214. public function fetchRow($result)
  215. {
  216. if (empty($result)) return false;
  217. $row = mysqli_fetch_assoc($result);
  218. if($row == null) $row = false; //Make sure MySQLi driver results are consistent with other database drivers
  219. return $row;
  220. }
  221. /**
  222. * @see DBManager::quote()
  223. */
  224. public function quote($string)
  225. {
  226. return mysqli_real_escape_string($this->getDatabase(),$this->quoteInternal($string));
  227. }
  228. /**
  229. * @see DBManager::connect()
  230. */
  231. public function connect(array $configOptions = null, $dieOnError = false)
  232. {
  233. global $sugar_config;
  234. if (is_null($configOptions))
  235. $configOptions = $sugar_config['dbconfig'];
  236. if(!isset($this->database)) {
  237. //mysqli connector has a separate parameter for port.. We need to separate it out from the host name
  238. $dbhost=$configOptions['db_host_name'];
  239. $dbport=$configOptions['db_port'] == '' ? null : $configOptions['db_port'];
  240. $pos=strpos($configOptions['db_host_name'],':');
  241. if ($pos !== false) {
  242. $dbhost=substr($configOptions['db_host_name'],0,$pos);
  243. $dbport=substr($configOptions['db_host_name'],$pos+1);
  244. }
  245. $this->database = mysqli_connect($dbhost,$configOptions['db_user_name'],$configOptions['db_password'],isset($configOptions['db_name'])?$configOptions['db_name']:'',$dbport);
  246. if(empty($this->database)) {
  247. $GLOBALS['log']->fatal("Could not connect to DB server ".$dbhost." as ".$configOptions['db_user_name'].". port " .$dbport . ": " . mysqli_connect_error());
  248. if($dieOnError) {
  249. if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) {
  250. sugar_die($GLOBALS['app_strings']['ERR_NO_DB']);
  251. } else {
  252. sugar_die("Could not connect to the database. Please refer to sugarcrm.log for details.");
  253. }
  254. } else {
  255. return false;
  256. }
  257. }
  258. }
  259. if(!empty($configOptions['db_name']) && !@mysqli_select_db($this->database,$configOptions['db_name'])) {
  260. $GLOBALS['log']->fatal( "Unable to select database {$configOptions['db_name']}: " . mysqli_connect_error());
  261. if($dieOnError) {
  262. if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) {
  263. sugar_die($GLOBALS['app_strings']['ERR_NO_DB']);
  264. } else {
  265. sugar_die("Could not connect to the database. Please refer to sugarcrm.log for details.");
  266. }
  267. } else {
  268. return false;
  269. }
  270. }
  271. // cn: using direct calls to prevent this from spamming the Logs
  272. mysqli_query($this->database,"SET CHARACTER SET utf8");
  273. $names = "SET NAMES 'utf8'";
  274. $collation = $this->getOption('collation');
  275. if(!empty($collation)) {
  276. $names .= " COLLATE '$collation'";
  277. }
  278. mysqli_query($this->database,$names);
  279. if($this->checkError('Could Not Connect', $dieOnError))
  280. $GLOBALS['log']->info("connected to db");
  281. $this->connectOptions = $configOptions;
  282. return true;
  283. }
  284. /**
  285. * (non-PHPdoc)
  286. * @see MysqlManager::lastDbError()
  287. */
  288. public function lastDbError()
  289. {
  290. if($this->database) {
  291. if(mysqli_errno($this->database)) {
  292. return "MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database);
  293. }
  294. } else {
  295. $err = mysqli_connect_error();
  296. if($err) {
  297. return $err;
  298. }
  299. }
  300. return false;
  301. }
  302. public function getDbInfo()
  303. {
  304. $charsets = $this->getCharsetInfo();
  305. $charset_str = array();
  306. foreach($charsets as $name => $value) {
  307. $charset_str[] = "$name = $value";
  308. }
  309. return array(
  310. "MySQLi Version" => @mysqli_get_client_info(),
  311. "MySQLi Host Info" => @mysqli_get_host_info($this->database),
  312. "MySQLi Server Info" => @mysqli_get_server_info($this->database),
  313. "MySQLi Client Encoding" => @mysqli_client_encoding($this->database),
  314. "MySQL Character Set Settings" => join(", ", $charset_str),
  315. );
  316. }
  317. /**
  318. * Select database
  319. * @param string $dbname
  320. */
  321. protected function selectDb($dbname)
  322. {
  323. return mysqli_select_db($this->getDatabase(), $dbname);
  324. }
  325. /**
  326. * Check if this driver can be used
  327. * @return bool
  328. */
  329. public function valid()
  330. {
  331. return function_exists("mysqli_connect") && empty($GLOBALS['sugar_config']['mysqli_disabled']);
  332. }
  333. }