]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/database/MysqliManager.php
Release 6.4.0
[Github/sugarcrm.git] / include / database / MysqliManager.php
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-2011 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 /*********************************************************************************
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
91 require_once('include/database/MysqlManager.php');
92
93 /**
94  * MySQL manager implementation for mysqli extension
95  */
96 class MysqliManager extends MysqlManager
97 {
98         /**
99          * @see DBManager::$dbType
100          */
101         public $dbType = 'mysql';
102         public $variant = 'mysqli';
103         public $priority = 10;
104         public $label = 'LBL_MYSQLI';
105
106         /**
107          * @see DBManager::$backendFunctions
108          */
109         protected $backendFunctions = array(
110                 'free_result'        => 'mysqli_free_result',
111                 'close'              => 'mysqli_close',
112                 'row_count'          => 'mysqli_num_rows',
113                 'affected_row_count' => 'mysqli_affected_rows',
114                 );
115
116         /**
117          * @see MysqlManager::query()
118          */
119         public function query($sql, $dieOnError = false, $msg = '', $suppress = false, $keepResult = false)
120         {
121                 if(is_array($sql)) {
122                         return $this->queryArray($sql, $dieOnError, $msg, $suppress);
123         }
124
125                 static $queryMD5 = array();
126
127                 parent::countQuery($sql);
128                 $GLOBALS['log']->info('Query:' . $sql);
129                 $this->checkConnection();
130                 $this->query_time = microtime(true);
131                 $this->lastsql = $sql;
132                 $result = $suppress?@mysqli_query($this->database,$sql):mysqli_query($this->database,$sql);
133                 $md5 = md5($sql);
134
135                 if (empty($queryMD5[$md5]))
136                         $queryMD5[$md5] = true;
137
138                 $this->query_time = microtime(true) - $this->query_time;
139                 $GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
140
141                 // This is some heavy duty debugging, leave commented out unless you need this:
142                 /*
143                 $bt = debug_backtrace();
144                 for ( $i = count($bt) ; $i-- ; $i > 0 ) {
145                         if ( strpos('MysqliManager.php',$bt[$i]['file']) === false ) {
146                                 $line = $bt[$i];
147                         }
148                 }
149
150                 $GLOBALS['log']->fatal("${line['file']}:${line['line']} ${line['function']} \nQuery: $sql\n");
151                 */
152
153
154                 if($keepResult)
155                         $this->lastResult = $result;
156                 $this->checkError($msg.' Query Failed: ' . $sql, $dieOnError);
157
158                 return $result;
159         }
160
161         /**
162          * Returns the number of rows affected by the last query
163          *
164          * @return int
165          */
166         public function getAffectedRowCount($result)
167         {
168                 return mysqli_affected_rows($this->getDatabase());
169         }
170
171         /**
172          * Returns the number of rows returned by the result
173          *
174          * This function can't be reliably implemented on most DB, do not use it.
175          * @abstract
176          * @deprecated
177          * @param  resource $result
178          * @return int
179          */
180         public function getRowCount($result)
181         {
182             return mysqli_num_rows($result);
183         }
184
185
186     /**
187          * Disconnects from the database
188          *
189          * Also handles any cleanup needed
190          */
191         public function disconnect()
192         {
193                 $GLOBALS['log']->debug('Calling MySQLi::disconnect()');
194                 if(!empty($this->database)){
195                         $this->freeResult();
196                         mysqli_close($this->database);
197                         $this->database = null;
198                 }
199         }
200
201         /**
202          * @see DBManager::freeDbResult()
203          */
204         protected function freeDbResult($dbResult)
205         {
206                 if(!empty($dbResult))
207                         mysqli_free_result($dbResult);
208         }
209
210         /**
211          * @see DBManager::getFieldsArray()
212          */
213         public function getFieldsArray($result, $make_lower_case = false)
214         {
215                 $field_array = array();
216
217                 if (!isset($result) || empty($result))
218                         return 0;
219
220                 $i = 0;
221                 while ($i < mysqli_num_fields($result)) {
222                         $meta = mysqli_fetch_field_direct($result, $i);
223                         if (!$meta)
224                                 return 0;
225
226                         if($make_lower_case == true)
227                                 $meta->name = strtolower($meta->name);
228
229                         $field_array[] = $meta->name;
230
231                         $i++;
232                 }
233
234                 return $field_array;
235         }
236
237         /**
238          * @see DBManager::fetchRow()
239          */
240         public function fetchRow($result)
241         {
242                 if (empty($result))     return false;
243
244                 $row = mysqli_fetch_assoc($result);
245                 if($row == null) $row = false; //Make sure MySQLi driver results are consistent with other database drivers
246                 return $row;
247         }
248
249         /**
250          * @see DBManager::quote()
251          */
252         public function quote($string)
253         {
254                 return mysqli_real_escape_string($this->getDatabase(),$this->quoteInternal($string));
255         }
256
257         /**
258          * @see DBManager::connect()
259          */
260         public function connect(array $configOptions = null, $dieOnError = false)
261         {
262                 global $sugar_config;
263
264                 if (is_null($configOptions))
265                         $configOptions = $sugar_config['dbconfig'];
266
267                 if(!isset($this->database)) {
268
269                         //mysqli connector has a separate parameter for port.. We need to separate it out from the host name
270                         $dbhost=$configOptions['db_host_name'];
271                         $dbport=null;
272                         $pos=strpos($configOptions['db_host_name'],':');
273                         if ($pos !== false) {
274                                 $dbhost=substr($configOptions['db_host_name'],0,$pos);
275                                 $dbport=substr($configOptions['db_host_name'],$pos+1);
276                         }
277
278                         $this->database = mysqli_connect($dbhost,$configOptions['db_user_name'],$configOptions['db_password'],isset($configOptions['db_name'])?$configOptions['db_name']:'',$dbport);
279                         if(empty($this->database)) {
280                                 $GLOBALS['log']->fatal("Could not connect to DB server ".$dbhost." as ".$configOptions['db_user_name'].". port " .$dbport . ": " . mysqli_connect_error());
281                                 if($dieOnError) {
282                                         if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) {
283                                                 sugar_die($GLOBALS['app_strings']['ERR_NO_DB']);
284                                         } else {
285                                                 sugar_die("Could not connect to the database. Please refer to sugarcrm.log for details.");
286                                         }
287                                 } else {
288                                         return false;
289                                 }
290                         }
291                 }
292
293                 if(!empty($configOptions['db_name']) && !@mysqli_select_db($this->database,$configOptions['db_name'])) {
294                         $GLOBALS['log']->fatal( "Unable to select database {$configOptions['db_name']}: " . mysqli_connect_error());
295                         if($dieOnError) {
296                                         if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) {
297                                                 sugar_die($GLOBALS['app_strings']['ERR_NO_DB']);
298                                         } else {
299                                                 sugar_die("Could not connect to the database. Please refer to sugarcrm.log for details.");
300                                         }
301                         } else {
302                                 return false;
303                         }
304             }
305
306                 // cn: using direct calls to prevent this from spamming the Logs
307             mysqli_query($this->database,"SET CHARACTER SET utf8");
308             $names = "SET NAMES 'utf8'";
309             $collation = $this->getOption('collation');
310             if(!empty($collation)) {
311                 $names .= " COLLATE '$collation'";
312                 }
313             mysqli_query($this->database,$names);
314
315                 if($this->checkError('Could Not Connect', $dieOnError))
316                         $GLOBALS['log']->info("connected to db");
317
318                 $this->connectOptions = $configOptions;
319                 return true;
320         }
321
322         /**
323          * (non-PHPdoc)
324          * @see MysqlManager::lastDbError()
325          */
326         public function lastDbError()
327         {
328                 if($this->database) {
329                     if(mysqli_errno($this->database)) {
330                             return "MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database);
331                     }
332                 } else {
333                         $err =  mysqli_connect_error();
334                         if($err) {
335                             return $err;
336                         }
337                 }
338
339                 return false;
340         }
341
342         public function getDbInfo()
343         {
344                 $charsets = $this->getCharsetInfo();
345                 $charset_str = array();
346                 foreach($charsets as $name => $value) {
347                         $charset_str[] = "$name = $value";
348                 }
349                 return array(
350                         "MySQLi Version" => @mysqli_get_client_info(),
351                         "MySQLi Host Info" => @mysqli_get_host_info($this->database),
352                         "MySQLi Server Info" => @mysqli_get_server_info($this->database),
353                         "MySQLi Client Encoding" =>  @mysqli_client_encoding($this->database),
354                         "MySQL Character Set Settings" => join(", ", $charset_str),
355                 );
356         }
357
358         /**
359          * Select database
360          * @param string $dbname
361          */
362         protected function selectDb($dbname)
363         {
364                 return mysqli_select_db($dbname);
365         }
366
367         /**
368          * Check if this driver can be used
369          * @return bool
370          */
371         public function valid()
372         {
373                 return function_exists("mysqli_connect") && empty($GLOBALS['sugar_config']['mysqli_disabled']);
374         }
375 }