PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/include/database/MysqliManager.php

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