2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
37 /*********************************************************************************
39 * Description: Includes generic helper functions used throughout the application.
40 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41 * All Rights Reserved.
42 * Contributor(s): ______________________________________..
43 ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/security_utils.php');
49 function make_sugar_config(&$sugar_config)
51 /* used to convert non-array config.php file to array format */
52 global $admin_export_only;
54 global $calculate_response_time;
55 global $create_default_user;
58 global $dbconfigoption;
59 global $default_action;
60 global $default_charset;
61 global $default_currency_name;
62 global $default_currency_symbol;
63 global $default_currency_iso4217;
64 global $defaultDateFormat;
65 global $default_language;
66 global $default_module;
67 global $default_password;
68 global $default_permission_mode;
69 global $default_theme;
70 global $defaultTimeFormat;
71 global $default_user_is_admin;
72 global $default_user_name;
73 global $disable_export;
74 global $disable_persistent_connections;
75 global $display_email_template_variable_chooser;
76 global $display_inbound_email_buttons;
77 global $history_max_viewed;
81 global $list_max_entries_per_page;
82 global $lock_default_user_name;
83 global $log_memory_usage;
84 global $requireAccounts;
85 global $RSS_CACHE_TIME;
89 global $sugar_version;
92 global $translation_string_prefix;
94 global $upload_badext;
96 global $upload_maxsize;
97 global $import_max_execution_time;
98 global $list_max_entries_per_subpanel;
99 global $passwordsetting;
101 // assumes the following variables must be set:
102 // $dbconfig, $dbconfigoption, $cache_dir, $import_dir, $session_dir, $site_URL, $tmp_dir, $upload_dir
104 $sugar_config = array (
105 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
106 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
107 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
108 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
109 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
110 'chartEngine' => 'Jit',
111 'date_formats' => empty($dateFormats) ? array(
112 'Y-m-d'=>'2010-12-23',
113 'd-m-Y' => '23-12-2010',
114 'm-d-Y'=>'12-23-2010',
115 'Y/m/d'=>'2010/12/23',
116 'd/m/Y' => '23/12/2010',
117 'm/d/Y'=>'12/23/2010',
118 'Y.m.d' => '2010.12.23',
119 'd.m.Y' => '23.12.2010',
120 'm.d.Y' => '12.23.2010'
122 'dbconfig' => $dbconfig, // this must be set!!
123 'dbconfigoption' => $dbconfigoption, // this must be set!!
124 'default_action' => empty($default_action) ? 'index' : $default_action,
125 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
126 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
127 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
128 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
129 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
130 'default_export_charset' => 'UTF-8',
131 'default_language' => empty($default_language) ? 'en_us' : $default_language,
132 'default_module' => empty($default_module) ? 'Home' : $default_module,
133 'default_password' => empty($default_password) ? '' : $default_password,
134 'default_permissions' => array (
140 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
141 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
142 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
143 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
144 'disable_export' => empty($disable_export) ? false : $disable_export,
145 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
146 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
147 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
148 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
149 'host_name' => empty($host_name) ? 'localhost' : $host_name,
150 'import_dir' => $import_dir, // this must be set!!
151 'import_max_records_per_file' => 100,
152 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
153 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
154 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
155 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
156 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
157 'portal_view' => 'single_user',
158 'resource_management' => array (
159 'special_query_limit' => 50000,
160 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
161 'default_limit' => 1000,
163 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
164 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
165 'session_dir' => $session_dir, // this must be set!!
166 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
167 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
168 'showThemePicker' => true,
169 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
170 'time_formats' => empty($timeFormats) ? array (
171 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
172 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
173 'tmp_dir' => $tmp_dir, // this must be set!!
174 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
175 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
176 'upload_badext' => empty($upload_badext) ? array (
177 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
178 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
179 'upload_dir' => $upload_dir, // this must be set!!
180 'upload_maxsize' => empty($upload_maxsize) ? 3000000 : $upload_maxsize,
181 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
182 'lock_homepage' => false,
183 'lock_subpanels' => false,
184 'max_dashlets_homepage' => 15,
185 'dashlet_display_row_options' => array('1','3','5','10'),
186 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
187 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
188 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
189 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
190 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
191 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
192 'default_call_status' => 'Planned',
193 'js_lang_version' => 1,
194 'passwordsetting' => empty($passwordsetting) ? array (
195 'SystemGeneratedPasswordON' => '',
196 'generatepasswordtmpl' => '',
197 'lostpasswordtmpl' => '',
198 'forgotpasswordON' => true,
199 'linkexpiration' => '1',
200 'linkexpirationtime' => '30',
201 'linkexpirationtype' => '1',
202 'systexpiration' => '0',
203 'systexpirationtime' => '',
204 'systexpirationtype' => '0',
205 'systexpirationlogin' => '',
206 ) : $passwordsetting,
210 function get_sugar_config_defaults() {
213 * used for getting base values for array style config.php. used by the
214 * installer and to fill in new entries on upgrades. see also:
218 $sugar_config_defaults = array (
219 'admin_export_only' => false,
220 'export_delimiter' => ',',
221 'cache_dir' => 'cache/',
222 'calculate_response_time' => true,
223 'create_default_user' => false,
224 'chartEngine' => 'Jit',
225 'date_formats' => array (
226 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
227 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
228 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
229 'dbconfigoption' => array (
230 'persistent' => true,
233 'seqname_format' => '%s_seq',
236 'default_action' => 'index',
237 'default_charset' => return_session_value_or_default('default_charset',
239 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
240 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
241 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
242 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
243 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
244 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
245 'default_date_format' => 'm/d/Y',
246 'default_export_charset' => 'UTF-8',
247 'default_language' => return_session_value_or_default('default_language',
249 'default_module' => 'Home',
250 'default_password' => '',
251 'default_permissions' => array (
257 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
258 'default_time_format' => 'h:ia',
259 'default_user_is_admin' => false,
260 'default_user_name' => '',
261 'disable_export' => false,
262 'disable_persistent_connections' =>
263 return_session_value_or_default('disable_persistent_connections',
265 'display_email_template_variable_chooser' => false,
266 'display_inbound_email_buttons' => false,
267 'dump_slow_queries' => false,
268 'email_default_editor' => 'html',
269 'email_default_client' => 'sugar',
270 'email_default_delete_attachments' => true,
271 'history_max_viewed' => 50,
272 'installer_locked' => true,
273 'import_max_records_per_file' => 100,
274 'languages' => array('en_us' => 'English (US)'),
275 'large_scale_test' => false,
276 'list_max_entries_per_page' => 20,
277 'list_max_entries_per_subpanel' => 10,
278 'lock_default_user_name' => false,
279 'log_memory_usage' => false,
280 'portal_view' => 'single_user',
281 'resource_management' => array (
282 'special_query_limit' => 50000,
283 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
284 'default_limit' => 1000,
286 'require_accounts' => true,
287 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
289 'save_query' => 'all',
290 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
291 'showThemePicker' => true,
292 'slow_query_time_msec' => '100',
294 'time_formats' => array (
295 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM',
296 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM' ),
297 'tracker_max_display_length' => 15,
298 'translation_string_prefix' =>
299 return_session_value_or_default('translation_string_prefix', false),
300 'upload_badext' => array (
301 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
302 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
303 'upload_maxsize' => 3000000,
304 'import_max_execution_time' => 3600,
305 // 'use_php_code_json' => returnPhpJsonStatus(),
306 'verify_client_ip' => true,
307 'js_custom_version' => '',
308 'js_lang_version' => 1,
309 'default_number_grouping_seperator' => ',',
310 'default_decimal_seperator' => '.',
311 'lock_homepage' => false,
312 'lock_subpanels' => false,
313 'max_dashlets_homepage' => '15',
314 'default_max_tabs' => '7',
315 'dashlet_display_row_options' => array('1','3','5','10'),
316 'default_subpanel_tabs' => true,
317 'default_subpanel_links' => false,
318 'default_swap_last_viewed' => false,
319 'default_swap_shortcuts' => false,
320 'default_navigation_paradigm' => 'gm',
321 'admin_access_control' => false,
322 'use_common_ml_dir' => false,
323 'common_ml_dir' => '',
325 'passwordsetting' => empty($passwordsetting) ? array (
326 'SystemGeneratedPasswordON' => '',
327 'generatepasswordtmpl' => '',
328 'lostpasswordtmpl' => '',
329 'forgotpasswordON' => false,
330 'linkexpiration' => '1',
331 'linkexpirationtime' => '30',
332 'linkexpirationtype' => '1',
333 'systexpiration' => '0',
334 'systexpirationtime' => '',
335 'systexpirationtype' => '0',
336 'systexpirationlogin' => '',
337 ) : $passwordsetting,
338 'use_real_names' => true,
341 if(!is_object($locale)) {
342 $locale = new Localization();
345 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
347 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
348 return( $sugar_config_defaults );
352 * @deprecated use SugarView::getMenu() instead
354 function load_menu($path){
357 if(file_exists($path . 'Menu.php'))
359 require($path . 'Menu.php');
361 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
363 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
365 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
367 require('custom/application/Ext/Menus/menu.ext.php');
373 * get_notify_template_file
374 * This function will return the location of the email notifications template to use
376 * @return string relative file path to email notifications template file
378 function get_notify_template_file($language){
380 * Order of operation:
381 * 1) custom version of specified language
382 * 2) stock version of specified language
383 * 3) custom version of en_us template
384 * 4) stock en_us template
387 // set $file to the base code template so it's set if none of the conditions pass
388 $file = "include/language/en_us.notify_template.html";
390 if(file_exists("custom/include/language/{$language}.notify_template.html")){
391 $file = "custom/include/language/{$language}.notify_template.html";
393 else if(file_exists("include/language/{$language}.notify_template.html")){
394 $file = "include/language/{$language}.notify_template.html";
396 else if(file_exists("custom/include/language/en_us.notify_template.html")){
397 $file = "custom/include/language/en_us.notify_template.html";
403 function sugar_config_union( $default, $override ){
404 // a little different then array_merge and array_merge_recursive. we want
405 // the second array to override the first array if the same value exists,
406 // otherwise merge the unique keys. it handles arrays of arrays recursively
407 // might be suitable for a generic array_union
408 if( !is_array( $override ) ){
411 foreach( $default as $key => $value ){
412 if( !array_key_exists($key, $override) ){
413 $override[$key] = $value;
415 else if( is_array( $key ) ){
416 $override[$key] = sugar_config_union( $value, $override[$key] );
422 function make_not_writable( $file ){
423 // Returns true if the given file/dir has been made not writable
425 if( is_file($file) || is_dir($file) ){
426 if( !is_writable($file) ){
430 $original_fileperms = fileperms($file);
432 // take away writable permissions
433 $new_fileperms = $original_fileperms & ~0x0092;
434 @sugar_chmod($file, $new_fileperms);
436 if( !is_writable($file) ){
445 /** This function returns the name of the person.
446 * It currently returns "first last". It should not put the space if either name is not available.
447 * It should not return errors if either name is not available.
448 * If no names are present, it will return ""
449 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
450 * All Rights Reserved.
451 * Contributor(s): ______________________________________..
453 function return_name($row, $first_column, $last_column)
459 if(isset($row[$first_column]))
461 $first_name = stripslashes($row[$first_column]);
464 if(isset($row[$last_column]))
466 $last_name = stripslashes($row[$last_column]);
469 $full_name = $first_name;
471 // If we have a first name and we have a last name
472 if($full_name != "" && $last_name != "")
474 // append a space, then the last name
475 $full_name .= " ".$last_name;
477 // If we have no first name, but we have a last name
478 else if($last_name != "")
480 // append the last name without the space.
481 $full_name .= $last_name;
488 function get_languages()
490 global $sugar_config;
491 $lang = $sugar_config['languages'];
492 if(!empty($sugar_config['disabled_languages'])){
493 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
494 unset($lang[$disable]);
500 function get_all_languages()
502 global $sugar_config;
503 return $sugar_config['languages'];
507 function get_language_display($key)
509 global $sugar_config;
510 return $sugar_config['languages'][$key];
513 function get_assigned_user_name($assigned_user_id, $is_group = '') {
514 static $saved_user_list = null;
516 if(empty($saved_user_list)) {
517 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
520 if(isset($saved_user_list[$assigned_user_id])) {
521 return $saved_user_list[$assigned_user_id];
528 * retrieves the user_name column value (login)
529 * @param string id GUID of user
532 function get_user_name($id) {
536 $db = DBManagerFactory::getInstance();
538 $q = "SELECT user_name FROM users WHERE id='{$id}'";
540 $a = $db->fetchByAssoc($r);
542 return (empty($a)) ? '' : $a['user_name'];
546 //TODO Update to use global cache
547 function get_user_array($add_blank=true, $status="Active", $assigned_user="", $use_real_name=false, $user_name_begins = null, $is_group=' AND portal_only=0 ', $from_cache = true) {
549 global $sugar_config;
553 $locale = new Localization();
556 $user_array = get_register_value('user_array', $add_blank. $status . $assigned_user);
558 if(empty($user_array)) {
559 $db = DBManagerFactory::getInstance();
560 $temp_result = Array();
561 // Including deleted users for now.
562 if (empty($status)) {
563 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$is_group;
566 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$is_group;
569 if (!empty($user_name_begins)) {
570 $query .= " AND user_name LIKE '$user_name_begins%' ";
572 if (!empty($assigned_user)) {
573 $query .= " OR id='$assigned_user'";
575 $query = $query.' ORDER BY user_name ASC';
576 $GLOBALS['log']->debug("get_user_array query: $query");
577 $result = $db->query($query, true, "Error filling in user array: ");
579 if ($add_blank==true) {
580 // Add in a blank row
581 $temp_result[''] = '';
584 // Get the id and the name.
585 while($row = $db->fetchByAssoc($result)) {
586 if($use_real_name == true || showFullName()) {
587 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
588 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
590 $temp_result[$row['id']] = $row['user_name'];
593 $temp_result[$row['id']] = $row['user_name'];
597 $user_array = $temp_result;
599 set_register_value('user_array', $add_blank. $status . $assigned_user, $temp_result);
608 * uses a different query to return a list of users than get_user_array()
609 * @param args string where clause entry
610 * @return array Array of Users' details that match passed criteria
612 function getUserArrayFromFullName($args, $hide_portal_users = false) {
614 $db = DBManagerFactory::getInstance();
617 if(strpos($args, " ")) {
618 $argArray = explode(" ", $args);
624 foreach($argArray as $arg) {
625 if(!empty($inClause)) {
631 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
634 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
635 if ( $hide_portal_users ) {
636 $query .= " portal_only=0 AND ";
639 $query .= " ORDER BY last_name ASC";
641 $r = $db->query($query);
643 while($a = $db->fetchByAssoc($r)) {
644 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
652 * based on user pref then system pref
654 function showFullName() {
655 global $sugar_config;
656 global $current_user;
657 static $showFullName = null;
659 if (is_null($showFullName)) {
660 $sysPref = !empty($sugar_config['use_real_names']);
661 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
663 if($userPref != null) {
664 $showFullName = ($userPref == 'on');
666 $showFullName = $sysPref;
670 return $showFullName;
673 function clean($string, $maxLength)
675 $string = substr($string, 0, $maxLength);
676 return escapeshellcmd($string);
680 * Copy the specified request variable to the member variable of the specified object.
681 * Do no copy if the member variable is already set.
682 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
683 * All Rights Reserved.
684 * Contributor(s): ______________________________________..
686 function safe_map($request_var, & $focus, $always_copy = false)
688 safe_map_named($request_var, $focus, $request_var, $always_copy);
692 * Copy the specified request variable to the member variable of the specified object.
693 * Do no copy if the member variable is already set.
694 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
695 * All Rights Reserved.
696 * Contributor(s): ______________________________________..
698 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
700 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
701 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
702 $focus->$member_var = $_REQUEST[$request_var];
707 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
709 * @param string $language specific language to load
710 * @return array lang strings
712 function return_app_list_strings_language($language)
714 global $app_list_strings;
715 global $sugar_config;
717 $cache_key = 'app_list_strings.'.$language;
719 // Check for cached value
720 $cache_entry = sugar_cache_retrieve($cache_key);
721 if(!empty($cache_entry))
726 $default_language = $sugar_config['default_language'];
727 $temp_app_list_strings = $app_list_strings;
730 if ($language != 'en_us') {
733 if ($default_language != 'en_us' && $language != $default_language) {
734 $langs[] = $default_language;
736 $langs[] = $language;
738 $app_list_strings_array = array();
740 foreach ( $langs as $lang ) {
741 $app_list_strings = array();
742 if(file_exists("include/language/$lang.lang.php")) {
743 include("include/language/$lang.lang.php");
744 $GLOBALS['log']->info("Found language file: $lang.lang.php");
746 if(file_exists("include/language/$lang.lang.override.php")) {
747 include("include/language/$lang.lang.override.php");
748 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
750 if(file_exists("include/language/$lang.lang.php.override")) {
751 include("include/language/$lang.lang.php.override");
752 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
755 $app_list_strings_array[] = $app_list_strings;
758 $app_list_strings = array();
759 foreach ( $app_list_strings_array as $app_list_strings_item ) {
760 $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
763 foreach ( $langs as $lang ) {
764 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
765 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
766 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
768 if(file_exists("custom/include/language/$lang.lang.php")) {
769 include("custom/include/language/$lang.lang.php");
770 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
774 if(!isset($app_list_strings)) {
775 $GLOBALS['log']->fatal("Unable to load the application language file for the selected language ($language) or the default language ($default_language) or the en_us language");
779 $return_value = $app_list_strings;
780 $app_list_strings = $temp_app_list_strings;
782 sugar_cache_put($cache_key, $return_value);
784 return $return_value;
788 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
789 * $GLOBALS['app_list_strings']['$key'] = $value, so we have to delete the original ones in app_list_strings and relace it with the custom ones.
790 * @param file string the language that you want include,
791 * @param app_list_strings array the golbal strings
795 function _mergeCustomAppListStrings($file , $app_list_strings){
796 $app_list_strings_original = $app_list_strings;
797 unset($app_list_strings);
798 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
799 // This way, language file can add items to save specific standard codelist from being overwritten
800 $exemptDropdowns = array();
802 if(!isset($app_list_strings) || !is_array($app_list_strings)){
803 return $app_list_strings_original;
805 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
807 // FG - bug 45525 - Specific codelists must NOT be overwritten
808 $exemptDropdowns[] = "moduleList";
809 $exemptDropdowns[] = "parent_type_display";
810 $exemptDropdowns[] = "record_type_display";
811 $exemptDropdowns[] = "record_type_display_notes";
813 foreach($app_list_strings as $key=>$value)
815 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
817 unset($app_list_strings_original["$key"]);
820 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
821 return $app_list_strings;
825 * This function retrieves an application language file and returns the array of strings included.
827 * @param string $language specific language to load
828 * @return array lang strings
830 function return_application_language($language)
832 global $app_strings, $sugar_config;
834 $cache_key = 'app_strings.'.$language;
836 // Check for cached value
837 $cache_entry = sugar_cache_retrieve($cache_key);
838 if(!empty($cache_entry))
843 $temp_app_strings = $app_strings;
844 $default_language = $sugar_config['default_language'];
847 if ($language != 'en_us') {
850 if ($default_language != 'en_us' && $language != $default_language) {
851 $langs[] = $default_language;
854 $langs[] = $language;
856 $app_strings_array = array();
858 foreach ( $langs as $lang ) {
859 $app_strings = array();
860 if(file_exists("include/language/$lang.lang.php")) {
861 include("include/language/$lang.lang.php");
862 $GLOBALS['log']->info("Found language file: $lang.lang.php");
864 if(file_exists("include/language/$lang.lang.override.php")) {
865 include("include/language/$lang.lang.override.php");
866 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
868 if(file_exists("include/language/$lang.lang.php.override")) {
869 include("include/language/$lang.lang.php.override");
870 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
872 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
873 include("custom/application/Ext/Language/$lang.lang.ext.php");
874 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
876 if(file_exists("custom/include/language/$lang.lang.php")) {
877 include("custom/include/language/$lang.lang.php");
878 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
880 $app_strings_array[] = $app_strings;
883 $app_strings = array();
884 foreach ( $app_strings_array as $app_strings_item ) {
885 $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
888 if(!isset($app_strings)) {
889 $GLOBALS['log']->fatal("Unable to load the application language strings");
893 // If we are in debug mode for translating, turn on the prefix now!
894 if($sugar_config['translation_string_prefix']) {
895 foreach($app_strings as $entry_key=>$entry_value) {
896 $app_strings[$entry_key] = $language.' '.$entry_value;
899 if(isset($_SESSION['show_deleted'])) {
900 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
901 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
902 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
903 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
906 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
908 $return_value = $app_strings;
909 $app_strings = $temp_app_strings;
911 sugar_cache_put($cache_key, $return_value);
913 return $return_value;
917 * This function retrieves a module's language file and returns the array of strings included.
919 * @param string $language specific language to load
920 * @param string $module module name to load strings for
921 * @param bool $refresh optional, true if you want to rebuild the language strings
922 * @return array lang strings
924 function return_module_language($language, $module, $refresh=false)
927 global $sugar_config;
928 global $currentModule;
930 // Jenny - Bug 8119: Need to check if $module is not empty
931 if (empty($module)) {
932 $stack = debug_backtrace();
933 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
937 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
938 // Check for cached value
939 $cache_entry = sugar_cache_retrieve($cache_key);
940 if(!empty($cache_entry))
945 // Store the current mod strings for later
946 $temp_mod_strings = $mod_strings;
947 $loaded_mod_strings = array();
948 $language_used = $language;
949 $default_language = $sugar_config['default_language'];
951 if(empty($language)) {
952 $language = $default_language;
955 // Bug 21559 - So we can get all the strings defined in the template, refresh
956 // the vardefs file if the cached language file doesn't exist.
957 if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/'. $module . '/language/'.$language.'.lang.php')
958 && !empty($GLOBALS['beanList'][$module])){
959 $object = $GLOBALS['beanList'][$module];
960 if ($object == 'aCase') {
963 VardefManager::refreshVardefs($module,$object);
966 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
968 // cn: bug 6048 - merge en_us with requested language
969 if($language != $sugar_config['default_language'])
970 $loaded_mod_strings = sugarArrayMerge(
971 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
975 // Load in en_us strings by default
976 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
977 $loaded_mod_strings = sugarArrayMerge(
978 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
982 // If we are in debug mode for translating, turn on the prefix now!
983 if($sugar_config['translation_string_prefix']) {
984 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
985 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
989 $return_value = $loaded_mod_strings;
990 if(!isset($mod_strings)){
991 $mod_strings = $return_value;
994 $mod_strings = $temp_mod_strings;
996 sugar_cache_put($cache_key, $return_value);
997 return $return_value;
1001 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1002 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1003 * All Rights Reserved.
1004 * Contributor(s): ______________________________________..
1005 * If you are using the current language, do not call this function unless you are loading it for the first time */
1006 function return_mod_list_strings_language($language,$module) {
1007 global $mod_list_strings;
1008 global $sugar_config;
1009 global $currentModule;
1011 $cache_key = "mod_list_str_lang.".$language.$module;
1013 // Check for cached value
1014 $cache_entry = sugar_cache_retrieve($cache_key);
1015 if(!empty($cache_entry))
1017 return $cache_entry;
1020 $language_used = $language;
1021 $temp_mod_list_strings = $mod_list_strings;
1022 $default_language = $sugar_config['default_language'];
1024 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1025 return $mod_list_strings;
1028 // cn: bug 6351 - include en_us if file langpack not available
1029 // cn: bug 6048 - merge en_us with requested language
1030 include("modules/$module/language/en_us.lang.php");
1031 $en_mod_list_strings = array();
1032 if($language_used != $default_language)
1033 $en_mod_list_strings = $mod_list_strings;
1035 if(file_exists("modules/$module/language/$language.lang.php")) {
1036 include("modules/$module/language/$language.lang.php");
1039 if(file_exists("modules/$module/language/$language.lang.override.php")){
1040 include("modules/$module/language/$language.lang.override.php");
1043 if(file_exists("modules/$module/language/$language.lang.php.override")){
1044 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1045 include("modules/$module/language/$language.lang.php.override");
1048 // cn: bug 6048 - merge en_us with requested language
1049 $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1051 // if we still don't have a language pack, then log an error
1052 if(!isset($mod_list_strings)) {
1053 $GLOBALS['log']->fatal("Unable to load the application list language file for the selected language($language) or the default language($default_language) for module({$module})");
1057 $return_value = $mod_list_strings;
1058 $mod_list_strings = $temp_mod_list_strings;
1060 sugar_cache_put($cache_key, $return_value);
1061 return $return_value;
1065 /** This function retrieves a theme's language file and returns the array of strings included.
1066 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1067 * All Rights Reserved.
1068 * Contributor(s): ______________________________________..
1070 function return_theme_language($language, $theme)
1072 global $mod_strings, $sugar_config, $currentModule;
1074 $language_used = $language;
1075 $default_language = $sugar_config['default_language'];
1077 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1078 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1079 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1081 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1082 echo 'Please Change:<br>' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php";
1083 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1085 if(!isset($theme_strings))
1087 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1088 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1089 $language_used = $default_language;
1092 if(!isset($theme_strings))
1094 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1098 // If we are in debug mode for translating, turn on the prefix now!
1099 if($sugar_config['translation_string_prefix'])
1101 foreach($theme_strings as $entry_key=>$entry_value)
1103 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1107 return $theme_strings;
1112 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1113 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1114 * All Rights Reserved.
1115 * Contributor(s): ______________________________________..
1117 function return_session_value_or_default($varname, $default)
1119 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1121 return $_SESSION[$varname];
1128 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1129 * It looks for the variable in the $_REQUEST array. If it is set and is not "" it will create a where clause out of it.
1130 * @param &$where_clauses - The array to append the clause to
1131 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1132 * @param $SQL_name - [Optional] If specified, this is the SQL column name that is used. If not specified, the $variable_name is used as the SQL_name.
1133 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1134 * All Rights Reserved.
1135 * Contributor(s): ______________________________________..
1137 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1139 if($SQL_name == null)
1141 $SQL_name = $variable_name;
1144 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1146 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1151 * Generate the appropriate SQL based on the where clauses.
1152 * @param $where_clauses - An Array of individual where clauses stored as strings
1153 * @returns string where_clause - The final SQL where clause to be executed.
1154 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1155 * All Rights Reserved.
1156 * Contributor(s): ______________________________________..
1158 function generate_where_statement($where_clauses)
1161 foreach($where_clauses as $clause)
1168 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1173 * determines if a passed string matches the criteria for a Sugar GUID
1174 * @param string $guid
1175 * @return bool False on failure
1177 function is_guid($guid) {
1178 if(strlen($guid) != 36) {
1182 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1191 * A temporary method of generating GUIDs of the correct format for our DB.
1192 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1194 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1195 * All Rights Reserved.
1196 * Contributor(s): ______________________________________..
1198 function create_guid()
1200 $microTime = microtime();
1201 list($a_dec, $a_sec) = explode(" ", $microTime);
1203 $dec_hex = dechex($a_dec* 1000000);
1204 $sec_hex = dechex($a_sec);
1206 ensure_length($dec_hex, 5);
1207 ensure_length($sec_hex, 6);
1211 $guid .= create_guid_section(3);
1213 $guid .= create_guid_section(4);
1215 $guid .= create_guid_section(4);
1217 $guid .= create_guid_section(4);
1220 $guid .= create_guid_section(6);
1226 function create_guid_section($characters)
1229 for($i=0; $i<$characters; $i++)
1231 $return .= dechex(mt_rand(0,15));
1236 function ensure_length(&$string, $length)
1238 $strlen = strlen($string);
1239 if($strlen < $length)
1241 $string = str_pad($string,$length,"0");
1243 else if($strlen > $length)
1245 $string = substr($string, 0, $length);
1249 function microtime_diff($a, $b) {
1250 list($a_dec, $a_sec) = explode(" ", $a);
1251 list($b_dec, $b_sec) = explode(" ", $b);
1252 return $b_sec - $a_sec + $b_dec - $a_dec;
1255 // check if Studio is displayed.
1256 function displayStudioForCurrentUser()
1258 global $current_user;
1259 if ( $current_user->isAdmin() ) {
1269 function displayWorkflowForCurrentUser()
1271 $_SESSION['display_workflow_for_user'] = false;
1275 // return an array with all modules where the user is an admin.
1276 function get_admin_modules_for_user($user) {
1277 $GLOBALS['log']->deprecated("get_admin_modules_for_user() is deprecated as of 6.2.2 and may disappear in the future, use Users->getDeveloperModules() instead");
1284 return($user->getDeveloperModules());
1288 function get_workflow_admin_modules_for_user($user){
1289 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1290 return $_SESSION['get_workflow_admin_modules_for_user'];
1294 $workflow_mod_list = array();
1295 foreach($moduleList as $module){
1296 $workflow_mod_list[$module] = $module;
1299 // This list is taken from teh previous version of workflow_utils.php
1300 $workflow_mod_list['Tasks'] = "Tasks";
1301 $workflow_mod_list['Calls'] = "Calls";
1302 $workflow_mod_list['Meetings'] = "Meetings";
1303 $workflow_mod_list['Notes'] = "Notes";
1304 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1305 $workflow_mod_list['Leads'] = "Leads";
1306 $workflow_mod_list['Opportunities'] = "Opportunities";
1309 $workflow_admin_modules = array();
1311 return $workflow_admin_modules;
1313 $actions = ACLAction::getUserActions($user->id);
1314 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1315 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1316 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1317 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1319 foreach ($workflow_mod_list as $key=>$val) {
1320 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1321 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1322 ($user->isDeveloperForModule($key))) {
1323 $workflow_admin_modules[$key] = $val;
1326 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1327 return ($workflow_admin_modules);
1330 // Check if user is admin for at least one module.
1331 function is_admin_for_any_module($user) {
1335 if($user->isAdmin()) {
1342 // Check if user is admin for a specific module.
1343 function is_admin_for_module($user,$module) {
1344 if (!isset($user)) {
1347 if ($user->isAdmin()) {
1355 * Check if user id belongs to a system admin.
1356 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1357 * All Rights Reserved.
1358 * Contributor(s): ______________________________________..
1360 function is_admin($user) {
1365 return $user->isAdmin();
1369 * Return the display name for a theme if it exists.
1370 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1371 * All Rights Reserved.
1372 * Contributor(s): ______________________________________..
1374 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1376 function get_theme_display($theme)
1378 return SugarThemeRegistry::get($theme)->name;
1382 * Return an array of directory names.
1383 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1384 * All Rights Reserved.
1385 * Contributor(s): ______________________________________..
1387 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1389 function get_themes()
1391 return SugarThemeRegistry::availableThemes();
1395 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1396 * Create HTML to display select options in a dropdown list. To be used inside
1397 * of a select statement in a form.
1398 * param $option_list - the array of strings to that contains the option list
1399 * param $selected - the string which contains the default value
1400 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1401 * All Rights Reserved.
1402 * Contributor(s): ______________________________________..
1404 function get_select_options ($option_list, $selected) {
1405 return get_select_options_with_id($option_list, $selected);
1409 * Create HTML to display select options in a dropdown list. To be used inside
1410 * of a select statement in a form. This method expects the option list to have keys and values. The keys are the ids. The values are the display strings.
1411 * param $option_list - the array of strings to that contains the option list
1412 * param $selected - the string which contains the default value
1413 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1414 * All Rights Reserved.
1415 * Contributor(s): ______________________________________..
1417 function get_select_options_with_id ($option_list, $selected_key) {
1418 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1423 * Create HTML to display select options in a dropdown list. To be used inside
1424 * of a select statement in a form. This method expects the option list to have keys and values. The keys are the ids. The values are the display strings.
1425 * param $label_list - the array of strings to that contains the option list
1426 * param $key_list - the array of strings to that contains the values list
1427 * param $selected - the string which contains the default value
1428 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1429 * All Rights Reserved.
1430 * Contributor(s): ______________________________________..
1432 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1433 global $app_strings;
1434 $select_options = "";
1436 //for setting null selection values to human readable --None--
1437 $pattern = "/'0?'></";
1438 $replacement = "''>".$app_strings['LBL_NONE']."<";
1440 $replacement .= "/OPTION>\n<OPTION value='__SugarMassUpdateClearField__'><"; // Giving the user the option to unset a drop down list. I.e. none means that it won't get updated
1443 if (empty($key_list)) $key_list = array();
1444 //create the type dropdown domain and set the selected value if $opp value already exists
1445 foreach ($key_list as $option_key=>$option_value) {
1447 $selected_string = '';
1448 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1449 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1450 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1452 $selected_string = 'selected ';
1455 $html_value = $option_key;
1457 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1459 $select_options = preg_replace($pattern, $replacement, $select_options);
1460 return $select_options;
1465 * Call this method instead of die().
1466 * Then we call the die method with the error message that is passed in.
1468 function sugar_die($error_message)
1472 die($error_message);
1477 * Create javascript to clear values of all elements in a form.
1478 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1479 * All Rights Reserved.
1480 * Contributor(s): ______________________________________..
1482 function get_clear_form_js () {
1483 $the_script = <<<EOQ
1484 <script type="text/javascript" language="JavaScript">
1485 function clear_form(form) {
1486 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1487 if(typeof(form.advanced) != 'undefined'){
1488 newLoc += '&advanced=' + form.advanced.value;
1490 document.location.href= newLoc;
1499 * Create javascript to set the cursor focus to specific field in a form
1500 * when the screen is rendered. The field name is currently hardcoded into the
1502 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1503 * All Rights Reserved.
1504 * Contributor(s): ______________________________________..
1506 function get_set_focus_js () {
1507 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1508 $the_script = <<<EOQ
1509 <script type="text/javascript" language="JavaScript">
1511 function set_focus() {
1512 if (document.forms.length > 0) {
1513 for (i = 0; i < document.forms.length; i++) {
1514 for (j = 0; j < document.forms[i].elements.length; j++) {
1515 var field = document.forms[i].elements[j];
1516 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1517 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1519 if (field.type == "text") {
1536 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1537 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1538 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1539 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1540 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1541 * the first - so the array is sorted by the last given column first, then the one before ...
1542 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1543 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1544 * All Rights Reserved.
1545 * Contributor(s): ______________________________________..
1547 function array_csort() {
1548 $args = func_get_args();
1549 $marray = array_shift($args);
1552 $msortline = "return(array_multisort(";
1553 foreach ($args as $arg) {
1555 if (is_string($arg)) {
1556 foreach ($marray as $row) {
1557 $sortarr[$i][] = $row[$arg];
1560 $sortarr[$i] = $arg;
1562 $msortline .= "\$sortarr[".$i."],";
1564 $msortline .= "\$marray));";
1571 * Converts localized date format string to jscalendar format
1572 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1573 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1574 * All Rights Reserved.
1575 * Contributor(s): ______________________________________..
1577 function parse_calendardate($local_format) {
1578 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1579 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1580 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1587 function translate($string, $mod='', $selectedValue=''){
1588 //$test_start = microtime();
1589 //static $mod_strings_results = array();
1591 global $current_language;
1593 if(isset($_REQUEST['login_language'])){
1594 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1596 $mod_strings = return_module_language($current_language, $mod);
1599 global $mod_strings;
1603 global $app_strings, $app_list_strings;
1605 if(isset($mod_strings[$string]))
1606 $returnValue = $mod_strings[$string];
1607 else if(isset($app_strings[$string]))
1608 $returnValue = $app_strings[$string];
1609 else if(isset($app_list_strings[$string]))
1610 $returnValue = $app_list_strings[$string];
1611 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1612 $returnValue = $app_list_strings['moduleList'][$string];
1615 //$test_end = microtime();
1617 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1619 // echo("translate results:");
1621 // $total_strings = 0;
1622 // foreach($mod_strings_results as $key=>$value)
1624 // echo("Module $key \t\t time $value \t\t<br>");
1625 // $total_time += $value;
1628 // echo("Total time: $total_time<br>");
1632 if(empty($returnValue)){
1636 if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1637 return $returnValue[$selectedValue];
1640 return $returnValue;
1643 function unTranslateNum($num) {
1645 static $num_grp_sep;
1646 global $current_user, $sugar_config;
1648 if($dec_sep == null) {
1649 $user_dec_sep = $current_user->getPreference('dec_sep');
1650 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1652 if($num_grp_sep == null) {
1653 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1654 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1657 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1658 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1663 function add_http($url) {
1664 if(!preg_match("@://@i", $url)) {
1666 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1670 return "{$scheme}://{$url}";
1677 * returns a default array of XSS tags to clean
1680 function getDefaultXssTags() {
1682 "applet" => "applet",
1687 "frameset" => "frameset",
1688 "iframe" => "iframe",
1689 "import" => "\?import",
1692 "object" => "object",
1693 "script" => "script",
1697 $ret = base64_encode(serialize($tmp));
1703 * Remove potential xss vectors from strings
1704 * @param string str String to search for XSS attack vectors
1705 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1708 function remove_xss($str, $cleanImg=true)
1710 $potentials = clean_xss($str, $cleanImg);
1711 if(is_array($potentials) && !empty($potentials)) {
1712 foreach($potentials as $bad) {
1713 $str = str_replace($bad, "", $str);
1720 * Detects typical XSS attack patterns
1721 * @param string str String to search for XSS attack vectors
1722 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1723 * @return array Array of matches, empty on clean string
1725 function clean_xss($str, $cleanImg=true) {
1726 global $sugar_config;
1728 if(empty($sugar_config['email_xss']))
1729 $sugar_config['email_xss'] = getDefaultXssTags();
1731 $arr = unserialize(base64_decode($sugar_config['email_xss']));
1734 foreach($arr as $v) {
1735 if(!empty($regex)) {
1741 $tag_regex = "#<({$regex})[^>]*>?#sim";
1743 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1744 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1745 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1746 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1748 $attribute_regex = "#<.+({$jsEvents})[^=>]*=[^>]*>#sim";
1749 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1750 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1751 $css_url = '#url\(.*\.\w+\)#';
1754 $str = str_replace("\t", "", $str);
1756 $matches = array_merge(
1757 xss_check_pattern($tag_regex, $str),
1758 xss_check_pattern($javascript_regex, $str)
1762 $jsMatches = xss_check_pattern($attribute_regex, $str);
1763 if(!empty($jsMatches)){
1764 preg_match_all($attribute_regex, $str, $newMatches, PREG_PATTERN_ORDER);
1765 if(!empty($newMatches[0][0])){
1766 $matches2 = array_merge(xss_check_pattern("#({$jsEvents})#sim", $newMatches[0][0]));
1767 $matches = array_merge($matches, $matches2);
1772 $matches = array_merge($matches,
1773 xss_check_pattern($imgsrc_regex, $str)
1777 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1778 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1780 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1781 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1782 // normalize whitelist
1783 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1784 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1787 foreach($cssUrlMatches[0] as $match) {
1788 $domain = strtolower(substr(strstr($match, "://"), 3));
1789 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1791 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1792 $matches[] = $match;
1797 $matches = array_merge($matches, $cssUrlMatches[0]);
1804 * Helper function used by clean_xss() to parse for known-bad vectors
1805 * @param string pattern Regex pattern to use
1806 * @param string str String to parse for badness
1809 function xss_check_pattern($pattern, $str) {
1810 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1815 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1817 * @param string $str
1818 * @param string $filter which corresponds to a regular expression to use; choices are:
1819 * "STANDARD" ( default )
1829 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1831 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1833 global $sugar_config;
1836 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1837 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1838 "FILE" => '#[^A-Z0-9\-_\.]#i',
1839 "NUMBER" => '#[^0-9\-]#i',
1840 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1841 "PATH_NO_URL" => '#://#i',
1842 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~]#i', /* range of allowed characters in a GET string */
1843 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1844 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1845 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1848 if (preg_match($filters[$filter], $str)) {
1849 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1850 $GLOBALS['log']->fatal("SECURITY: bad data passed in; string: {$str}");
1852 if ( $dieOnBadData ) {
1853 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1862 function clean_special_arguments() {
1863 if(isset($_SERVER['PHP_SELF'])) {
1864 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1866 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1867 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1868 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1869 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1870 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1871 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1872 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1873 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1874 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1875 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1876 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1877 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1878 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1879 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1880 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1881 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1882 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1883 clean_superglobals('offset', 'ALPHANUM');
1884 clean_superglobals('return_action');
1885 clean_superglobals('return_module');
1890 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1892 function clean_superglobals($key, $filter = 'STANDARD') {
1893 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1894 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1895 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1898 function set_superglobals($key, $val){
1900 $_POST[$key] = $val;
1901 $_REQUEST[$key] = $val;
1904 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1905 function clean_incoming_data() {
1906 global $sugar_config;
1908 if (get_magic_quotes_gpc() == 1) {
1909 $req = array_map("preprocess_param", $_REQUEST);
1910 $post = array_map("preprocess_param", $_POST);
1911 $get = array_map("preprocess_param", $_GET);
1914 $req = array_map("securexss", $_REQUEST);
1915 $post = array_map("securexss", $_POST);
1916 $get = array_map("securexss", $_GET);
1919 // PHP cannot stomp out superglobals reliably
1920 foreach($post as $k => $v) { $_POST[$k] = $v; }
1921 foreach($get as $k => $v) { $_GET[$k] = $v; }
1922 foreach($req as $k => $v) {
1924 //ensure the keys are safe as well
1927 // Any additional variables that need to be cleaned should be added here
1928 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1929 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1930 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1931 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1932 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1933 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
1934 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
1935 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
1936 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
1937 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
1938 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
1939 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
1940 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
1942 if(isset($_REQUEST['lvso'])){
1943 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
1945 // Clean "offset" and "order_by" parameters in URL
1946 foreach ($_REQUEST as $key => $val) {
1947 if (str_end($key, "_offset")) {
1948 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
1949 set_superglobals($key, $_REQUEST[$key]);
1951 elseif (str_end($key, "_ORDER_BY")) {
1952 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
1953 set_superglobals($key, $_REQUEST[$key]);
1961 // Returns TRUE if $str begins with $begin
1962 function str_begin($str, $begin) {
1963 return (substr($str, 0, strlen($begin)) == $begin);
1966 // Returns TRUE if $str ends with $end
1967 function str_end($str, $end) {
1968 return (substr($str, strlen($str) - strlen($end)) == $end);
1971 function securexss($value) {
1972 if(is_array($value)){
1974 foreach($value as $key=>$val){
1975 $new[$key] = securexss($val);
1979 static $xss_cleanup= array('"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
1980 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
1981 $value = preg_replace('/javascript:/i', 'java script:', $value);
1982 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
1985 function securexsskey($value, $die=true){
1986 global $sugar_config;
1988 preg_match("/[\'\"\<\>]/", $value, $matches);
1989 if(!empty($matches)){
1991 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1993 unset($_REQUEST[$value]);
1994 unset($_POST[$value]);
1995 unset($_GET[$value]);
2000 function preprocess_param($value){
2001 if(is_string($value)){
2002 if(get_magic_quotes_gpc() == 1){
2003 $value = stripslashes($value);
2006 $value = securexss($value);
2015 function set_register_value($category, $name, $value){
2016 return sugar_cache_put("{$category}:{$name}", $value);
2019 function get_register_value($category,$name){
2020 return sugar_cache_retrieve("{$category}:{$name}");
2023 // this function cleans id's when being imported
2024 function convert_id($string)
2026 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2028 // single quotes are essential here,
2029 // or alternative escape all $ as \$
2031 'return ord($matches[0]);'
2036 * @deprecated use SugarTheme::getImage()
2038 function get_image($image,$other_attributes,$width="",$height="")
2040 return SugarThemeRegistry::current()->getImage(basename($image),
2042 empty($width) ? null : $width,
2043 empty($height) ? null : $height
2047 * @deprecated use SugarTheme::getImageURL()
2049 function getImagePath($image_name)
2051 return SugarThemeRegistry::current()->getImageURL($image_name);
2054 function getWebPath($relative_path){
2055 //if it has a :// then it isn't a relative path
2056 if(substr_count($relative_path, '://') > 0) return $relative_path;
2057 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2058 return $relative_path;
2061 function getJSPath($relative_path, $additional_attrs=''){
2062 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2063 if(empty($GLOBALS['sugar_config']['js_custom_version']))$GLOBALS['sugar_config']['js_custom_version'] = 1;
2064 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2065 $path = $relative_path . '?s=' . $js_version_key . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] ;
2066 if ( inDeveloperMode() ) $path .= '&developerMode='.mt_rand();
2067 if(!empty($additonal_attrs)) $path .= '&' . $additional_attrs;
2071 function getSWFPath($relative_path, $additional_params=''){
2072 $path = $relative_path;
2073 if (!empty($additional_params)){
2074 $path .= '?' . $additional_params;
2076 if (defined('TEMPLATE_URL')){
2077 $path = TEMPLATE_URL . '/' . $path;
2086 function getSQLDate($date_str)
2088 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2090 if ( strlen($match[2]) == 1)
2092 $match[2] = "0".$match[2];
2094 if ( strlen($match[1]) == 1)
2096 $match[1] = "0".$match[1];
2098 return "{$match[3]}-{$match[1]}-{$match[2]}";
2100 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2102 if ( strlen($match[2]) == 1)
2104 $match[2] = "0".$match[2];
2106 if ( strlen($match[1]) == 1)
2108 $match[1] = "0".$match[1];
2110 return "{$match[3]}-{$match[1]}-{$match[2]}";
2118 function clone_history(&$db, $from_id,$to_id, $to_type)
2123 require_once('include/upload_file.php');
2124 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2126 $location=array('Email'=>"modules/Emails/Email.php",
2127 'Call'=>"modules/Calls/Call.php",
2128 'Meeting'=>"modules/Meetings/Meeting.php",
2129 'Note'=>"modules/Notes/Note.php",
2130 'Tasks'=>"modules/Tasks/Task.php",
2134 foreach($tables as $table=>$bean_class)
2137 if (!class_exists($bean_class))
2139 require_once($location[$bean_class]);
2142 $bProcessingNotes=false;
2143 if ($table=='notes')
2145 $bProcessingNotes=true;
2147 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2148 $results = $db->query($query);
2149 while($row = $db->fetchByAssoc($results))
2151 //retrieve existing record.
2152 $bean= new $bean_class();
2153 $bean->retrieve($row['id']);
2154 //process for new instance.
2155 if ($bProcessingNotes)
2157 $old_note_id=$row['id'];
2158 $old_filename=$bean->filename;
2161 $bean->parent_id=$to_id;
2162 $bean->parent_type=$to_type;
2163 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2165 $bean->contact_id=$to_id;
2167 $bean->update_date_modified = false;
2168 $bean->update_modified_by = false;
2169 if(isset($bean->date_modified))
2170 $bean->date_modified = $timedate->to_db($bean->date_modified);
2171 if(isset($bean->date_entered))
2172 $bean->date_entered = $timedate->to_db($bean->date_entered);
2174 $new_id=$bean->save();
2176 //duplicate the file now. for notes.
2177 if ($bProcessingNotes && !empty($old_filename))
2179 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2181 //reset the values needed for attachment duplication.
2188 function values_to_keys($array)
2190 $new_array = array();
2191 if(!is_array($array))
2195 foreach($array as $arr){
2196 $new_array[$arr] = $arr;
2201 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2203 foreach($tables as $table)
2206 if ($table == 'emails_beans') {
2207 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2209 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2211 $results = $db->query($query);
2212 while($row = $db->fetchByAssoc($results))
2214 $query = "INSERT INTO $table ";
2217 $row[$from_column] = $to_id;
2218 $row['id'] = create_guid();
2219 if ($table=='emails_beans') {
2220 $row['bean_module'] =='Contacts';
2223 foreach($row as $name=>$value)
2229 $values .= "'$value'";
2232 $names .= ', '. $name;
2233 $values .= ", '$value'";
2236 $query .= "($names) VALUES ($values)";
2242 function get_unlinked_email_query($type, $bean) {
2243 global $current_user;
2245 $return_array['select']='SELECT emails.id ';
2246 $return_array['from']='FROM emails ';
2247 $return_array['where']="";
2248 $return_array['join'] = " JOIN (select distinct email_id from emails_email_addr_rel eear
2250 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2251 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2252 where eear.deleted=0 and eear.email_id not in
2253 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2254 ) derivedemails on derivedemails.email_id = emails.id";
2255 $return_array['join_tables'][0] = '';
2257 if (isset($type) and isset($type['return_as_array']) and $type['return_as_array']==true) {
2258 return $return_array;
2261 return $return_array['select'] . $return_array['from'] . $return_array['where'];
2265 * Check to see if the number is empty or non-zero
2269 function number_empty($value)
2271 return empty($value) && $value != '0';
2274 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2277 require_once($beanFiles[$bean_name]);
2278 $focus = new $bean_name();
2279 $user_array = array();
2280 $user_array = get_register_value('select_array',$bean_name. $display_columns. $where . $order_by);
2284 $db = DBManagerFactory::getInstance();
2285 $temp_result = Array();
2286 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2290 $query .= $where." AND ";
2293 $query .= " {$focus->table_name}.deleted=0";
2295 if ( $order_by != '')
2297 $query .= " order by {$focus->table_name}.{$order_by}";
2300 $GLOBALS['log']->debug("get_user_array query: $query");
2301 $result = $db->query($query, true, "Error filling in user array: ");
2303 if ($add_blank==true){
2304 // Add in a blank row
2305 if($blank_is_none == true) { // set 'blank row' to "--None--"
2306 global $app_strings;
2307 $temp_result[''] = $app_strings['LBL_NONE'];
2309 $temp_result[''] = '';
2313 // Get the id and the name.
2314 while($row = $db->fetchByAssoc($result))
2316 $temp_result[$row['id']] = $row['display'];
2319 $user_array = $temp_result;
2320 set_register_value('select_array',$bean_name. $display_columns. $where . $order_by,$temp_result);
2329 * @param unknown_type $listArray
2331 // function parse_list_modules
2332 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2333 function parse_list_modules(&$listArray)
2335 global $modListHeader;
2336 $returnArray = array();
2338 foreach($listArray as $optionName => $optionVal)
2340 if(array_key_exists($optionName, $modListHeader))
2342 $returnArray[$optionName] = $optionVal;
2345 // special case for projects
2346 if(array_key_exists('Project', $modListHeader))
2348 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2351 $acldenied = ACLController::disabledModuleList($listArray,false);
2352 foreach($acldenied as $denied){
2353 unset($returnArray[$denied]);
2355 asort($returnArray);
2357 return $returnArray;
2360 function display_notice($msg = false){
2361 global $error_notice;
2362 //no error notice - lets just display the error to the user
2363 if(!isset($error_notice)){
2364 echo '<br>'.$msg . '<br>';
2366 $error_notice .= $msg . '<br>';
2370 /* checks if it is a number that atleast has the plus at the beggining
2372 function skype_formatted($number){
2373 //kbrill - BUG #15375
2374 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2377 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2379 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2382 function format_skype($number) {
2383 return preg_replace('/[^\+0-9]/','',$number);
2386 function insert_charset_header() {
2387 header('Content-Type: text/html; charset=UTF-8');
2390 function getCurrentURL()
2393 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2398 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2402 function javascript_escape($str) {
2405 for($i = 0; $i < strlen($str); $i++) {
2407 if(ord(substr($str, $i, 1))==10){
2409 }elseif(ord(substr($str, $i, 1))==13){
2413 $new_str .= $str{$i};
2417 $new_str = str_replace("'", "\\'", $new_str);
2422 function js_escape($str, $keep=true){
2423 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2426 $str = javascript_escape($str);
2429 $str = str_replace("'", " ", $str);
2430 $str = str_replace('"', " ", $str);
2435 //end function js_escape
2438 function br2nl($str) {
2439 $regex = "#<[^>]+br.+?>#i";
2440 preg_match_all($regex, $str, $matches);
2442 foreach($matches[0] as $match) {
2443 $str = str_replace($match, "<br>", $str);
2446 $brs = array('<br>','<br/>', '<br />');
2447 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2448 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2449 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2450 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2456 * Private helper function for displaying the contents of a given variable.
2457 * This function is only intended to be used for SugarCRM internal development.
2458 * The ppd stands for Pre Print Die.
2460 function _ppd($mixed)
2466 * Private helper function for displaying the contents of a given variable in
2467 * the Logger. This function is only intended to be used for SugarCRM internal
2468 * development. The pp stands for Pre Print.
2469 * @param $mixed var to print_r()
2470 * @param $die boolean end script flow
2471 * @param $displayStackTrace also show stack trace
2473 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2477 * private helper function to quickly show the major, direct, field attributes of a given bean.
2478 * The ppf stands for Pre[formatted] Print Focus [object]
2479 * @param object bean The focus bean
2481 function _ppf($bean, $die=false) {
2487 * Private helper function for displaying the contents of a given variable.
2488 * This function is only intended to be used for SugarCRM internal development.
2489 * The pp stands for Pre Print.
2491 function _pp($mixed)
2496 * Private helper function for displaying the contents of a given variable.
2497 * This function is only intended to be used for SugarCRM internal development.
2498 * The pp stands for Pre Print.
2500 function _pstack_trace($mixed=NULL)
2505 * Private helper function for displaying the contents of a given variable.
2506 * This function is only intended to be used for SugarCRM internal development.
2507 * The pp stands for Pre Print Trace.
2509 function _ppt($mixed, $textOnly=false)
2514 * Private helper function for displaying the contents of a given variable.
2515 * This function is only intended to be used for SugarCRM internal development.
2516 * The pp stands for Pre Print Trace Die.
2518 function _pptd($mixed)
2523 * Private helper function for decoding javascript UTF8
2524 * This function is only intended to be used for SugarCRM internal development.
2526 function decodeJavascriptUTF8($str) {
2530 * Will check if a given PHP version string is supported (tested on this ver),
2531 * unsupported (results unknown), or invalid (something will break on this
2532 * ver). Do not pass in any pararameter to default to a check against the
2533 * current environment's PHP version.
2535 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2537 function check_php_version($sys_php_version = '') {
2538 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2539 // versions below $min_considered_php_version considered invalid by default,
2540 // versions equal to or above this ver will be considered depending
2541 // on the rules that follow
2542 $min_considered_php_version = '5.2.1';
2544 // only the supported versions,
2545 // should be mutually exclusive with $invalid_php_versions
2546 $supported_php_versions = array (
2547 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2549 //Find out what Database the system is using.
2550 global $sugar_config;
2552 if (isset($_REQUEST['setup_db_type'])) {
2553 $dbType = $_REQUEST['setup_db_type'];
2554 } else if (isset ($sugar_config['dbconfig']) && isset ($sugar_config['dbconfig']['db_type'])) {
2555 $dbType = $sugar_config['dbconfig']['db_type'];
2558 // invalid versions above the $min_considered_php_version,
2559 // should be mutually exclusive with $supported_php_versions
2561 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2562 $invalid_php_versions = array('5.2.7');
2564 // default unsupported
2567 // versions below $min_considered_php_version are invalid
2568 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2572 // supported version check overrides default unsupported
2573 foreach($supported_php_versions as $ver) {
2574 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2580 // invalid version check overrides default unsupported
2581 foreach($invalid_php_versions as $ver) {
2582 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2588 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2589 //and the php version contains 'rh' characters
2590 if(strpos($sys_php_version, 'rh') !== false) {
2598 * Will check if a given IIS version string is supported (tested on this ver),
2599 * unsupported (results unknown), or invalid (something will break on this
2602 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2604 function check_iis_version($sys_iis_version = '') {
2606 $server_software = $_SERVER["SERVER_SOFTWARE"];
2608 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2609 $iis_version = $out[1][0];
2611 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2613 // versions below $min_considered_iis_version considered invalid by default,
2614 // versions equal to or above this ver will be considered depending
2615 // on the rules that follow
2616 $min_considered_iis_version = '6.0';
2618 // only the supported versions,
2619 // should be mutually exclusive with $invalid_iis_versions
2620 $supported_iis_versions = array ('6.0', '7.0',);
2621 $unsupported_iis_versions = array();
2622 $invalid_iis_versions = array('5.0',);
2624 // default unsupported
2627 // versions below $min_considered_iis_version are invalid
2628 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2632 // supported version check overrides default unsupported
2633 foreach($supported_iis_versions as $ver) {
2634 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2640 // unsupported version check overrides default unsupported
2641 foreach($unsupported_iis_versions as $ver) {
2642 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2648 // invalid version check overrides default unsupported
2649 foreach($invalid_iis_versions as $ver) {
2650 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2659 function pre_login_check(){
2660 global $action, $login_error;
2661 if(!empty($action)&& $action == 'Login'){
2663 if(!empty($login_error)){
2664 $login_error = htmlentities($login_error);
2665 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2666 $_SESSION['login_error'] = $login_error;
2668 function set_focus() {}
2669 if(document.getElementById("post_error")) {
2670 document.getElementById("post_error").innerHTML="'. $login_error. '";
2671 document.getElementById("cant_login").value=1;
2672 document.getElementById("login_button").disabled = true;
2673 document.getElementById("user_name").disabled = true;
2674 //document.getElementById("user_password").disabled = true;
2683 function sugar_cleanup($exit = false) {
2684 static $called = false;
2687 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2688 chdir(realpath(dirname(__FILE__) . '/..'));
2689 global $sugar_config;
2690 require_once('include/utils/LogicHook.php');
2691 LogicHook::initialize();
2692 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2694 //added this check to avoid errors during install.
2695 if (empty($sugar_config['dbconfig'])) {
2696 if ($exit) exit; else return;
2699 if (!class_exists('Tracker', true)) {
2700 require_once 'modules/Trackers/Tracker.php';
2703 // Now write the cached tracker_queries
2704 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2705 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2706 $GLOBALS['current_user']->savePreferencesToDB();
2709 //check to see if this is not an ajax call AND the user preference error flag is set
2711 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2712 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2713 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2714 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2717 global $app_strings;
2718 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2719 $err_mess = $app_strings['ERROR_USER_PREFS'];
2720 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2723 ajaxStatus.flashStatus('$err_mess',7000);
2729 if(class_exists('DBManagerFactory')) {
2730 $db = DBManagerFactory::getInstance();
2738 register_shutdown_function('sugar_cleanup');
2742 check_logic_hook - checks to see if your custom logic is in the logic file
2743 if not, it will add it. If the file isn't built yet, it will create the file
2746 function check_logic_hook_file($module_name, $event, $action_array){
2747 require_once('include/utils/logic_utils.php');
2750 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2752 $hook_array = get_hook_array($module_name);
2754 if(check_existing_element($hook_array, $event, $action_array)==true){
2755 //the hook at hand is present, so do nothing
2760 if(!empty($hook_array[$event]))
2762 $logic_count = count($hook_array[$event]);
2765 if($action_array[0]==""){
2766 $action_array[0] = $logic_count + 1;
2768 $hook_array[$event][] = $action_array;
2771 //end if the file exists already
2774 if($action_array[0]==""){
2775 $action_array[0] = 1;
2777 $hook_array = array();
2778 $hook_array[$event][] = $action_array;
2779 //end if else file exists already
2781 if($add_logic == true){
2783 //reorder array by element[0]
2784 //$hook_array = reorder_array($hook_array, $event);
2785 //!!!Finish this above TODO
2787 $new_contents = replace_or_add_logic_type($hook_array);
2788 write_logic_file($module_name, $new_contents);
2790 //end if add_element is true
2793 //end function check_logic_hook_file
2796 function remove_logic_hook($module_name, $event, $action_array) {
2797 require_once('include/utils/logic_utils.php');
2800 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2801 // The file exists, let's make sure the hook is there
2802 $hook_array = get_hook_array($module_name);
2804 if(check_existing_element($hook_array, $event, $action_array)==true){
2805 // The hook is there, time to take it out.
2807 foreach ( $hook_array[$event] as $i => $hook ) {
2808 // We don't do a full comparison below just in case the filename changes
2809 if ( $hook[0] == $action_array[0]
2810 && $hook[1] == $action_array[1]
2811 && $hook[3] == $action_array[3]
2812 && $hook[4] == $action_array[4] ) {
2813 unset($hook_array[$event][$i]);
2817 $new_contents = replace_or_add_logic_type($hook_array);
2818 write_logic_file($module_name, $new_contents);
2824 function display_stack_trace($textOnly=false){
2826 $stack = debug_backtrace();
2828 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2836 foreach($stack as $item) {
2842 if(isset($item['file']))
2843 $file = $item['file'];
2844 if(isset($item['class']))
2845 $class = $item['class'];
2846 if(isset($item['line']))
2847 $line = $item['line'];
2848 if(isset($item['function']))
2849 $function = $item['function'];
2853 $out .= '<font color="black"><b>';
2859 $out .= '</b></font><font color="blue">';
2862 $out .= "[L:{$line}]";
2865 $out .= '</font><font color="red">';
2868 $out .= "({$class}:{$function})";
2871 $out .= '</font><br>';
2883 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2884 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2885 $halt_script = true;
2887 case 2048: return; //depricated we have lots of these ignore them
2890 if ( error_reporting() & E_NOTICE ) {
2891 $halt_script = false;
2897 case E_USER_WARNING:
2898 case E_COMPILE_WARNING:
2899 case E_CORE_WARNING:
2902 $halt_script = false;
2907 case E_COMPILE_ERROR:
2911 $type = "Fatal Error";
2916 $type = "Parse Error";
2920 //don't know what it is might not be so bad
2921 $halt_script = false;
2922 $type = "Unknown Error ($errno)";
2925 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
2927 display_stack_trace();
2937 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
2939 set_error_handler('StackTraceErrorHandler');
2941 function get_sub_cookies($name){
2943 if(isset($_COOKIE[$name])){
2944 $subs = explode('#', $_COOKIE[$name]);
2945 foreach($subs as $cookie){
2946 if(!empty($cookie)){
2947 $cookie = explode('=', $cookie);
2949 $cookies[$cookie[0]] = $cookie[1];
2958 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
2960 if(!empty($sub_object_array)){
2962 foreach($sub_object_array as $sub_object){
2964 //run_second level is set to true if you need to remove sub-sub components
2965 if($run_second_level==true){
2967 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
2969 //end if run_second_level is true
2971 $sub_object->mark_deleted($sub_object->id);
2972 //end foreach sub component
2974 //end if this is not empty
2977 //end function mark_delete_components
2981 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
2983 function return_bytes($val)
2986 $last = strtolower($val{strlen($val)-1});
2990 // The 'G' modifier is available since PHP 5.1.0
3003 * Adds the href HTML tags around any URL in the $string
3005 function url2html($string) {
3007 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3008 return $return_string;
3010 // End customization by Julian
3013 * tries to determine whether the Host machine is a Windows machine
3015 function is_windows() {
3016 static $is_windows = null;
3017 if (!isset($is_windows)) {
3018 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3024 * equivalent for windows filesystem for PHP's is_writable()
3025 * @param string file Full path to the file/dir
3026 * @return bool true if writable
3028 function is_writable_windows($file) {
3029 if($file{strlen($file)-1}=='/') {
3030 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3033 // the assumption here is that Windows has an inherited permissions scheme
3034 // any file that is a descendant of an unwritable directory will inherit
3035 // that property and will trigger a failure below.
3040 $file = str_replace("/", '\\', $file);
3042 if(file_exists($file)) {
3043 if (!($f = @sugar_fopen($file, 'r+')))
3049 if(!($f = @sugar_fopen($file, 'w')))
3058 * best guesses Timezone based on webserver's TZ settings
3060 function lookupTimezone($userOffset = 0)
3062 return TimeDate::guessTimezone($userOffset);
3065 function convert_module_to_singular($module_array){
3068 foreach($module_array as $key => $value){
3069 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3071 if($value=="Cases") {
3072 $module_array[$key] = "Case";
3074 if($key=="projecttask"){
3075 $module_array['ProjectTask'] = "Project Task";
3076 unset($module_array[$key]);
3080 return $module_array;
3082 //end function convert_module_to_singular
3086 * Given the bean_name which may be plural or singular return the singular
3087 * bean_name. This is important when you need to include files.
3089 function get_singular_bean_name($bean_name){
3090 global $beanFiles, $beanList;
3091 if(array_key_exists($bean_name, $beanList)){
3092 return $beanList[$bean_name];
3099 function get_label($label_tag, $temp_module_strings){
3100 global $app_strings;
3101 if(!empty($temp_module_strings[$label_tag])){
3103 $label_name = $temp_module_strings[$label_tag];
3105 if(!empty($app_strings[$label_tag])){
3106 $label_name = $app_strings[$label_tag];
3108 $label_name = $label_tag;
3113 //end function get_label
3117 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3119 $rel_list = array();
3121 foreach($focus->relationship_fields as $rel_key => $rel_value){
3122 if($rel_value == $relationship_name){
3123 $temp_bean = get_module_info($tar_rel_module);
3124 // echo $focus->$rel_key;
3125 $temp_bean->retrieve($focus->$rel_key);
3126 if($temp_bean->id!=""){
3128 $rel_list[] = $temp_bean;
3134 foreach($focus->field_defs as $field_name => $field_def){
3135 //Check if the relationship_name matches a "relate" field
3136 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3137 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3138 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3139 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3141 $temp_bean = get_module_info($tar_rel_module);
3142 // echo $focus->$field_def['id_name'];
3143 $temp_bean->retrieve($focus->$field_def['id_name']);
3144 if($temp_bean->id!=""){
3146 $rel_list[] = $temp_bean;
3149 //Check if the relationship_name matches a "link" in a relate field
3150 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3151 $temp_bean = get_module_info($tar_rel_module);
3152 // echo $focus->$rel_value['id_name'];
3153 $temp_bean->retrieve($focus->$rel_value['id_name']);
3154 if($temp_bean->id!=""){
3156 $rel_list[] = $temp_bean;
3162 // special case for unlisted parent-type relationships
3163 if($focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3164 $temp_bean = get_module_info($tar_rel_module);
3165 $temp_bean->retrieve($focus->parent_id);
3166 if($temp_bean->id!=""){
3167 $rel_list[] = $temp_bean;
3174 //end function search_filter_rel_info
3177 function get_module_info($module_name){
3181 //Get dictionary and focus data for module
3182 $vardef_name = $beanList[$module_name];
3184 if($vardef_name=="aCase"){
3185 $class_name = "Case";
3187 $class_name = $vardef_name;
3190 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3194 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3196 $module_bean = new $vardef_name();
3197 return $module_bean;
3198 //end function get_module_table
3202 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3204 * @param string $moduleName
3206 function get_valid_bean_name($module_name){
3209 $vardef_name = $beanList[$module_name];
3210 if($vardef_name=="aCase"){
3211 $bean_name = "Case";
3213 $bean_name = $vardef_name;
3220 function checkAuthUserStatus(){
3227 * This function returns an array of phpinfo() results that can be parsed and
3228 * used to figure out what version we run, what modules are compiled in, etc.
3229 * @param $level int info level constant (1,2,4,8...64);
3230 * @return $returnInfo array array of info about the PHP environment
3231 * @author original by "code at adspeed dot com" Fron php.net
3232 * @author customized for Sugar by Chris N.
3234 function getPhpInfo($level=-1) {
3235 /** Name (constant) Value Description
3236 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3237 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3238 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3239 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3240 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3241 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3242 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3243 INFO_ALL -1 Shows all of the above. This is the default value.
3247 $phpinfo = ob_get_contents();
3250 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3251 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3252 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3253 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3256 $returnInfo = array();
3258 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3259 $returnInfo['PHP Version'] = $version[1];
3263 for ($i=1; $i<count($parsedInfo); $i++) {
3264 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3265 $vName = trim($match[1]);
3266 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3268 foreach ($parsedInfo2 AS $vOne) {
3269 $vPat = '<info>([^<]+)<\/info>';
3270 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3271 $vPat2 = "/$vPat\s*$vPat/";
3273 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3274 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3275 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3276 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3288 * This function will take a string that has tokens like {0}, {1} and will replace
3289 * those tokens with the args provided
3290 * @param $format string to format
3291 * @param $args args to replace
3292 * @return $result a formatted string
3294 function string_format($format, $args){
3298 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3299 * IN () fails and IN ('') works.
3301 if (count($args) == 1)
3304 $singleArgument = current($args);
3305 if (empty($singleArgument))
3307 return str_replace("{0}", "''", $result);
3312 for($i = 0; $i < count($args); $i++){
3313 $result = str_replace('{'.$i.'}', $args[$i], $result);
3319 * Generate a string for displaying a unique identifier that is composed
3320 * of a system_id and number. This is use to allow us to generate quote
3321 * numbers using a DB auto-increment key from offline clients and still
3322 * have the number be unique (since it is modified by the system_id.
3324 * @param $num of bean
3325 * @param $system_id from system
3326 * @return $result a formatted string
3328 function format_number_display($num, $system_id){
3329 global $sugar_config;
3330 if(isset($num) && !empty($num)){
3331 $num=unformat_number($num);
3332 if(isset($system_id) && $system_id == 1){
3333 return sprintf("%d", $num);
3336 return sprintf("%d-%d", $num, $system_id);
3340 function checkLoginUserStatus(){
3344 * This function will take a number and system_id and format
3345 * @param $url URL containing host to append port
3346 * @param $port the port number - if '' is passed, no change to url
3347 * @return $resulturl the new URL with the port appended to the host
3349 function appendPortToHost($url, $port)
3353 // if no port, don't change the url
3356 $split = explode("/", $url);
3357 //check if it starts with http, in case they didn't include that in url
3358 if(str_begin($url, 'http'))
3360 //third index ($split[2]) will be the host
3361 $split[2] .= ":".$port;
3363 else // otherwise assumed to start with host name
3365 //first index ($split[0]) will be the host
3366 $split[0] .= ":".$port;
3369 $resulturl = implode("/", $split);
3376 * Singleton to return JSON object
3377 * @return JSON object
3379 function getJSONobj() {
3380 static $json = null;
3382 require_once('include/JSON.php');
3383 $json = new JSON(JSON_LOOSE_TYPE);
3388 require_once('include/utils/db_utils.php');
3389 //check to see if custom utils exists
3390 if(file_exists('custom/include/custom_utils.php')){
3391 include_once('custom/include/custom_utils.php');
3396 * Set default php.ini settings for entry points
3398 function setPhpIniSettings() {
3400 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3402 if(function_exists('gzclose') && headers_sent() == false) {
3403 ini_set('zlib.output_compression', 1);
3407 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3409 /*if(function_exists('mb_strlen')) {
3410 ini_set('mbstring.func_overload', 7);
3411 ini_set('mbstring.internal_encoding', 'UTF-8');
3415 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3416 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3417 $backtrack_limit = ini_get('pcre.backtrack_limit');
3418 if(!empty($backtrack_limit)) {
3419 ini_set('pcre.backtrack_limit', '-1');
3423 if(ini_get("mssql.charset")) {
3424 ini_set('mssql.charset', "UTF-8");
3429 * like array_merge() but will handle array elements that are themselves arrays;
3430 * PHP's version just overwrites the element with the new one.
3432 * @internal Note that this function deviates from the internal array_merge()
3433 * functions in that it does does not treat numeric keys differently
3434 * than string keys. Additionally, it deviates from
3435 * array_merge_recursive() by not creating an array when like values
3438 * @param array gimp the array whose values will be overloaded
3439 * @param array dom the array whose values will pwn the gimp's
3440 * @return array beaten gimp
3442 function sugarArrayMerge($gimp, $dom) {
3443 if(is_array($gimp) && is_array($dom)) {
3444 foreach($dom as $domKey => $domVal) {
3445 if(array_key_exists($domKey, $gimp)) {
3446 if(is_array($domVal)) {
3448 foreach ( $domVal as $domArrKey => $domArrVal )
3449 $tempArr[$domArrKey] = $domArrVal;
3450 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3451 if ( !array_key_exists($gimpArrKey, $tempArr) )
3452 $tempArr[$gimpArrKey] = $gimpArrVal;
3453 $gimp[$domKey] = $tempArr;
3455 $gimp[$domKey] = $domVal;
3458 $gimp[$domKey] = $domVal;
3462 // if the passed value for gimp isn't an array, then return the $dom
3463 elseif(is_array($dom))
3470 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3472 * @param array gimp the array whose values will be overloaded
3473 * @param array dom the array whose values will pwn the gimp's
3474 * @return array beaten gimp
3476 function sugarArrayMergeRecursive($gimp, $dom) {
3477 if(is_array($gimp) && is_array($dom)) {
3478 foreach($dom as $domKey => $domVal) {
3479 if(array_key_exists($domKey, $gimp)) {
3480 if(is_array($domVal) && is_array($gimp[$domKey])) {
3481 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3483 $gimp[$domKey] = $domVal;
3486 $gimp[$domKey] = $domVal;
3490 // if the passed value for gimp isn't an array, then return the $dom
3491 elseif(is_array($dom))
3498 * finds the correctly working versions of PHP-JSON
3499 * @return bool True if NOT found or WRONG version
3501 function returnPhpJsonStatus() {
3502 if(function_exists('json_encode')) {
3503 $phpInfo = getPhpInfo(8);
3504 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3506 return true; // not found
3511 * getTrackerSubstring
3513 * Returns a [number]-char or less string for the Tracker to display in the header
3514 * based on the tracker_max_display_length setting in config.php. If not set,
3515 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3517 * @param string name field for a given Object
3518 * @return string [number]-char formatted string if length of string exceeds the max allowed
3520 function getTrackerSubstring($name) {
3521 static $max_tracker_item_length;
3524 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3525 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3527 global $sugar_config;
3529 if(!isset($max_tracker_item_length)) {
3530 if(isset($sugar_config['tracker_max_display_length'])) {
3531 $max_tracker_item_length = (is_int($sugar_config['tracker_max_display_length']) && $sugar_config['tracker_max_display_length'] > 0 && $sugar_config['tracker_max_display_length'] < 50) ? $sugar_config['tracker_max_display_length'] : 15;
3533 $max_tracker_item_length = 15;
3537 if($strlen > $max_tracker_item_length) {
3538 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length, "UTF-8");
3545 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3546 $where_clauses= array();
3548 $table_name=$bean->object_name;
3549 foreach ($field_list[$module] as $field=>$parms) {
3550 if(isset($values[$field]) && $values[$field] != "") {
3552 if (!empty($parms['operator'])) {
3553 $operator=$parms['operator'];
3555 if (is_array($values[$field])) {
3558 foreach ($values[$field] as $key => $val) {
3559 if ($val != ' ' and $val != '') {
3560 if (!empty($field_value)) {
3563 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3567 $field_value=$GLOBALS['db']->quote($values[$field]);
3569 //set db_fields array.
3570 if (!isset($parms['db_field']) ) {
3571 $parms['db_field'] = array($field);
3573 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3574 global $current_user;
3575 $field_value = $GLOBALS['db']->quote($current_user->id);
3581 if ($field_value != '') {
3583 foreach ($parms['db_field'] as $db_field) {
3584 if (strstr($db_field,'.')===false) {
3585 $db_field=$bean->table_name.".".$db_field;
3587 if ($GLOBALS['db']->dbType=='oci8' && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3588 $db_field='upper('.$db_field.")";
3589 $field_value=strtoupper($field_value);
3593 if (!empty($where)) {
3596 switch (strtolower($operator)) {
3598 $where .= $db_field . " like '".$field_value.$like_char."'";
3601 $where .= $db_field . " in (".$field_value.')';
3604 $where .= $db_field . " = '".$field_value ."'";
3609 if (!empty($where)) {
3611 array_push($where_clauses, '( '.$where.' )');
3613 array_push($where_clauses, $where);
3618 if ($add_custom_fields) {
3619 require_once('modules/DynamicFields/DynamicField.php');
3620 $bean->setupCustomFields($module);
3621 $bean->custom_fields->setWhereClauses($where_clauses);
3623 return $where_clauses;
3626 function add_quotes($str) {
3631 * This function will rebuild the config file
3632 * @param $sugar_config
3633 * @param $sugar_version
3634 * @return bool true if successful
3636 function rebuildConfigFile($sugar_config, $sugar_version) {
3637 // add defaults to missing values of in-memory sugar_config
3638 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3639 // need to override version with default no matter what
3640 $sugar_config['sugar_version'] = $sugar_version;
3642 ksort( $sugar_config );
3644 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3653 * getJavascriptSiteURL
3654 * This function returns a URL for the client javascript calls to access
3655 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3656 * are used to access the site. Thus, the hostname in the URL returned may
3657 * not always match that of $sugar_config['site_url']. Basically, the
3658 * assumption is that however the user accessed the website is how they
3659 * will continue to with subsequent javascript requests. If the variable
3660 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3661 * @return $site_url The url used to refer to the website
3663 function getJavascriptSiteURL() {
3664 global $sugar_config;
3665 if(!empty($_SERVER['HTTP_REFERER'])) {
3666 $url = parse_url($_SERVER['HTTP_REFERER']);
3667 $replacement_url = $url['scheme']."://".$url['host'];
3668 if(!empty($url['port']))
3669 $replacement_url .= ':'.$url['port'];
3670 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3672 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3673 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3674 $site_url = preg_replace('/^http\:/','https:',$site_url);
3677 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3681 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3682 function add_squotes($str) {
3683 return "'" . $str . "'";
3687 // recursive function to count the number of levels within an array
3688 function array_depth($array, $depth_count=-1, $depth_array=array()){
3690 if (is_array($array)){
3691 foreach ($array as $key => $value){
3692 $depth_array[] = array_depth($value, $depth_count);
3696 return $depth_count;
3698 foreach ($depth_array as $value){
3699 $depth_count = $value > $depth_count ? $value : $depth_count;
3701 return $depth_count;
3705 * Creates a new Group User
3706 * @param string $name Name of Group User
3707 * @return string GUID of new Group User
3709 function createGroupUser($name) {
3712 $group = new User();
3713 $group->user_name = $name;
3714 $group->last_name = $name;
3715 $group->is_group = 1;
3716 $group->deleted = 0;
3717 $group->status = 'Active'; // cn: bug 6711
3718 $group->setPreference('timezone', TimeDate::userTimezone());
3725 * Helper function to locate an icon file given only a name
3726 * Searches through the various paths for the file
3727 * @param string iconFileName The filename of the icon
3728 * @return string Relative pathname of the located icon, or '' if not found
3731 function _getIcon($iconFileName)
3733 $iconPath = SugarThemeRegistry::current()->getImageURL("icon_{$iconFileName}.gif");
3734 //First try un-ucfirst-ing the icon name
3735 if ( empty($iconPath) )
3736 $iconPath = SugarThemeRegistry::current()->getImageURL(
3737 "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif");
3738 //Next try removing the icon prefix
3739 if ( empty($iconPath) )
3740 $iconPath = SugarThemeRegistry::current()->getImageURL("{$iconFileName}.gif");
3745 * Function to grab the correct icon image for Studio
3746 * @param string $iconFileName Name of the icon file
3747 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3748 * @param string $width Width of image
3749 * @param string $height Height of image
3750 * @param string $align Alignment of image
3751 * @return string $string <img> tag with corresponding image
3754 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline' )
3756 global $app_strings, $theme;
3758 $iconPath = _getIcon($iconFileName);
3759 if(empty($iconPath)){
3760 $iconPath = _getIcon($altFileName);
3761 if (empty($iconPath))
3763 return $app_strings['LBL_NO_IMAGE'];
3766 return '<img border="0" src="'.$iconPath.'" width="'.$width.'" height="'.$height.'" align="'.$align.'">';
3770 * Function to grab the correct icon image for Dashlets Dialog
3771 * @param string $filename Location of the icon file
3772 * @param string $module Name of the module to fall back onto if file does not exist
3773 * @param string $width Width of image
3774 * @param string $height Height of image
3775 * @param string $align Alignment of image
3776 * @return string $string <img> tag with corresponding image
3779 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle'){
3780 global $app_strings, $theme;
3781 $icon_path = _getIcon($module . "_32");
3782 if (empty($icon_path))
3784 $icon_path = _getIcon($module);
3786 if(empty($icon_path)){
3787 $icon = $app_strings['LBL_NO_IMAGE'];
3790 $icon = '<img border="0" src="'.$icon_path.'" width="'.$width.'" height="'.$height.'" align="'.$align.'">';
3795 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3796 function html_entity_decode_utf8($string)
3799 // replace numeric entities
3800 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3801 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3802 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
3803 // replace literal entities
3804 if (!isset($trans_tbl))
3806 $trans_tbl = array();
3807 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3808 $trans_tbl[$key] = utf8_encode($val);
3810 return strtr($string, $trans_tbl);
3813 // Returns the utf string corresponding to the unicode value
3814 function code2utf($num)
3816 if ($num < 128) return chr($num);
3817 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3818 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3819 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3823 function str_split_php4($string, $length = 1) {
3824 $string_length = strlen($string);
3827 if ($length > $string_length) {
3828 // use the string_length as the string is shorter than the length
3829 $length = $string_length;
3831 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3832 $return[] = substr($string, $cursor, $length);
3837 if (version_compare(phpversion(), '5.0.0', '<')) {
3838 function str_split($string, $length = 1) {
3839 return str_split_php4($string, $length);
3844 * Invoked when connected to mssql. checks if we have freetds version of mssql library.
3845 * the response is put into a global variable.
3847 function is_freetds() {
3850 if (isset($GLOBALS['mssql_library_version'])) {
3851 if ($GLOBALS['mssql_library_version']=='freetds') {
3859 $info=ob_get_contents();
3862 if (strpos($info,'FreeTDS') !== false) {
3863 $GLOBALS['mssql_library_version']='freetds';
3866 $GLOBALS['mssql_library_version']='regular';
3874 * stripos - Find position of first occurrence of a case-insensitive string
3876 * The function is being defined for systems with PHP version < 5.
3879 if (!function_exists("stripos")){
3880 function stripos($haystack,$needle,$offset=0){
3881 return strpos(strtolower($haystack),strtolower($needle),$offset);
3886 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3888 * @todo this won't work completely right until we impliment css compression and combination
3889 * for now, we'll just include the last css file found.
3891 * @return chart.css file to use
3893 function chartStyle()
3895 return SugarThemeRegistry::current()->getCSSURL('chart.css');
3899 * Chart dashlet helper functions that returns the correct XML color file for charts,
3900 * dependent on the current theme.
3902 * @return sugarColors.xml to use
3904 function chartColors()
3906 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
3907 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
3908 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
3910 /* End Chart Dashlet helper functions */
3913 * This function is designed to set up the php enviroment
3914 * for AJAX requests.
3917 function ajaxInit() {
3918 ini_set('display_errors', 'false');
3922 * Returns an absolute path from the given path, determining if it is relative or absolute
3924 * @param string $path
3927 function getAbsolutePath(
3929 $currentServer = false
3932 $path = trim($path);
3934 // try to match absolute paths like \\server\share, /directory or c:\
3935 if ( ( substr($path,0,2) == '\\\\' )
3936 || ( $path[0] == '/' )
3937 || preg_match('/^[A-z]:/i',$path)
3941 return getcwd().'/'.$path;
3945 * Returns the bean object of the given module
3947 * @deprecated use SugarModule::loadBean() instead
3948 * @param string $module
3955 return SugarModule::get($module)->loadBean();
3960 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
3962 function isTouchScreen()
3964 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
3966 // first check if we have forced use of the touch enhanced interface
3967 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
3971 // next check if we should use the touch interface with our device
3972 if ( strpos($ua, 'ipad') !== false ) {
3980 * Returns the shortcut keys to access the shortcut links. Shortcut
3981 * keys vary depending on browser versions and operating systems.
3982 * @return String value of the shortcut keys
3984 function get_alt_hot_key() {
3986 if ( isset($_SERVER['HTTP_USER_AGENT']) )
3987 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
3988 $isMac = strpos($ua, 'mac') !== false;
3989 $isLinux = strpos($ua, 'linux') !== false;
3991 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
3992 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
3993 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
3996 return $isMac ? 'Ctrl+' : 'Alt+';
3999 function can_start_session(){
4000 if(!empty($_GET['PHPSESSID'])) {
4003 $session_id = session_id();
4004 return empty($session_id) ? true : false;
4007 function load_link_class($properties){
4009 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4010 require_once($properties['link_file']);
4011 $class = $properties['link_class'];
4017 function inDeveloperMode()
4019 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4023 * Filter the protocol list for inbound email accounts.
4025 * @param array $protocol
4027 function filterInboundEmailPopSelection($protocol)
4029 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4031 if( isset($protocol['pop3']) )
4032 unset($protocol['pop3']);
4035 $protocol['pop3'] = 'POP3';
4041 * The function is used because currently we are not supporting mbstring.func_overload
4042 * For some user using mssql without FreeTDS, they may store multibyte charaters in varchar using latin_general collation. It cannot store so many mutilbyte characters, so we need to use strlen.
4043 * The varchar in MySQL, Orcale, and nvarchar in FreeTDS, we can store $length mutilbyte charaters in it. we need mb_substr to keep more info.
4044 * @returns the substred strings.
4046 function sugar_substr($string, $length, $charset='UTF-8') {
4047 if($GLOBALS['db']->dbType == 'mssql' && empty($GLOBALS['db']->isFreeTDS)) {
4048 if(strlen($string) > $length) {
4049 $string = trim(substr(trim($string),0,$length));
4053 if(mb_strlen($string,$charset) > $length) {
4054 $string = trim(mb_substr(trim($string),0,$length,$charset));
4061 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4062 * This will work even without setting the mbstring.*encoding
4064 function sugar_ucfirst($string, $charset='UTF-8') {
4065 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4072 function unencodeMultienum($string) {
4073 if (is_array($string))
4077 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4078 $string = substr(substr($string, 1), 0, strlen($string) -2);
4081 return explode('^,^', $string);
4084 function encodeMultienumValue($arr) {
4085 if (!is_array($arr))
4091 $string = "^" . implode('^,^', $arr) . "^";
4097 * create_export_query is used for export and massupdate
4098 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4099 * This function will correct the where clause and output necessary join condition for them
4100 * @param $module: the module name
4101 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4102 * @param $where: where clauses
4103 * @return $ret_array['where']: corrected where clause
4104 * @return $ret_array['join']: extra join condition
4106 function create_export_query_relate_link_patch($module, $searchFields, $where){
4107 if(file_exists('modules/'.$module.'/SearchForm.html')){
4108 $ret_array['where'] = $where;
4111 $seed = loadBean($module);
4112 foreach($seed->field_defs as $name=>$field)
4115 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4116 $seed->load_relationship($field['link']);
4118 if(empty($join_type))
4120 $params['join_type'] = ' LEFT JOIN ';
4124 $params['join_type'] = $join_type;
4126 if(isset($data['join_name']))
4128 $params['join_table_alias'] = $field['join_name'];
4132 $params['join_table_alias'] = 'join_'.$field['name'];
4135 if(isset($data['join_link_name']))
4137 $params['join_table_link_alias'] = $field['join_link_name'];
4141 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4143 $join = $seed->$field['link']->getJoin($params, true);
4144 $join_table_alias = 'join_'.$field['name'];
4145 if(isset($field['db_concat_fields'])){
4146 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4147 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4149 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4153 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4158 * We need to clear all the js cache files, including the js language files in serval places in MB. So I extract them into a util function here.
4159 * @Depends on QuickRepairAndRebuild.php
4160 * @Relate bug 30642 ,23177
4162 function clearAllJsAndJsLangFilesWithoutOutput(){
4163 global $current_language , $mod_strings;
4164 $MBmodStrings = $mod_strings;
4165 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4166 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4167 $repair = new RepairAndClear();
4168 $repair->module_list = array();
4169 $repair->show_output = false;
4170 $repair->clearJsLangFiles();
4171 $repair->clearJsFiles();
4172 $mod_strings = $MBmodStrings;
4176 * This function will allow you to get a variable value from query string
4178 function getVariableFromQueryString($variable, $string){
4180 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4190 * should_hide_iframes
4191 * This is a helper method to determine whether or not to show iframes (My Sites) related
4192 * information in the application.
4194 * @return boolean flag indicating whether or not iframes module should be hidden
4196 function should_hide_iframes() {
4197 //Remove the MySites module
4198 if(file_exists('modules/iFrames/iFrame.php')) {
4199 if(!class_exists("iFrame")) {
4200 require_once('modules/iFrames/iFrame.php');
4208 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4210 * @param string $version
4211 * @return string RC, BETA, GA
4213 function getVersionStatus($version){
4214 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4215 return strtoupper($matches[1]);
4222 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4223 * 5.5.1RC1 then return 5.5.1
4225 * @param string $version
4228 function getMajorMinorVersion($version){
4229 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4230 $version = $matches2[1];
4231 $arr = explode('.', $version);
4232 if(count($arr) > 2){
4234 $version = substr($version, 0, 3);
4242 * Return string composed of seconds & microseconds of current time, without dots
4245 function sugar_microtime()
4247 $now = explode(' ', microtime());
4248 $unique_id = $now[1].str_replace('.', '', $now[0]);
4253 * Extract urls from a piece of text
4255 * @return array of urls found in $string
4257 function getUrls($string)
4259 $lines = explode("<br>", trim($string));
4261 foreach($lines as $line){
4262 $regex = '/http?\:\/\/[^\" ]+/i';
4263 preg_match_all($regex, $line, $matches);
4264 foreach($matches[0] as $match){
4273 * Sanitize image file from hostile content
4274 * @param string $path Image file
4275 * @param bool $jpeg Accept only JPEGs?
4277 function verify_image_file($path, $jpeg = false)
4279 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4280 $img = imagecreatefromstring(file_get_contents($path));
4284 $img_size = getimagesize($path);
4285 $filetype = $img_size['mime'];
4286 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4287 if($filetype == "image/jpeg" || $jpeg) {
4288 if(imagejpeg($img, $path)) {
4291 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4292 imagealphablending($img, true);
4293 imagesavealpha($img, true);
4294 if(imagepng($img, $path)) {
4301 // check image manually
4302 $fp = fopen($path, "r");
4303 if(!$fp) return false;
4304 $data = fread($fp, 4096);
4306 if(preg_match("/<(html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
4308 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4317 * Verify uploaded image
4318 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4319 * @param string $path Image path
4320 * @param bool $jpeg_only Accept only JPEGs?
4322 function verify_uploaded_image($path, $jpeg_only = false)
4324 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4326 $supportedExtensions['png'] = 'image/png';
4329 if(!file_exists($path) || !is_file($path)) {
4333 $img_size = getimagesize($path);
4334 $filetype = $img_size['mime'];
4335 $ext = end(explode(".", $path));
4336 if(substr_count('..', $path) > 0 || $ext === $path || !in_array(strtolower($ext), array_keys($supportedExtensions)) ||
4337 !in_array($filetype, array_values($supportedExtensions))) {
4340 return verify_image_file($path, $jpeg_only);
4344 * @param $input - the input string to sanitize
4345 * @param int $quotes - use quotes
4346 * @param string $charset - the default charset
4347 * @param bool $remove - strip tags or not
4348 * @return string - the sanitized string
4350 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4352 return htmlentities($input, $quotes, $charset);