2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 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;
85 global $requireAccounts;
86 global $RSS_CACHE_TIME;
90 global $sugar_version;
93 global $translation_string_prefix;
95 global $upload_badext;
97 global $upload_maxsize;
98 global $import_max_execution_time;
99 global $list_max_entries_per_subpanel;
100 global $passwordsetting;
102 // assumes the following variables must be set:
103 // $dbconfig, $dbconfigoption, $cache_dir, $session_dir, $site_URL, $upload_dir
105 $sugar_config = array (
106 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
107 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
108 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
109 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
110 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
111 'chartEngine' => 'Jit',
112 'date_formats' => empty($dateFormats) ? array(
113 'Y-m-d'=>'2010-12-23',
114 'd-m-Y' => '23-12-2010',
115 'm-d-Y'=>'12-23-2010',
116 'Y/m/d'=>'2010/12/23',
117 'd/m/Y' => '23/12/2010',
118 'm/d/Y'=>'12/23/2010',
119 'Y.m.d' => '2010.12.23',
120 'd.m.Y' => '23.12.2010',
121 'm.d.Y' => '12.23.2010'
123 'dbconfig' => $dbconfig, // this must be set!!
124 'dbconfigoption' => $dbconfigoption, // this must be set!!
125 'default_action' => empty($default_action) ? 'index' : $default_action,
126 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
127 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
128 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
129 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
130 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
131 'default_locale_name_format' => empty($defaultNameFormat) ? 's f l' : $defaultNameFormat,
132 'default_export_charset' => 'UTF-8',
133 'default_language' => empty($default_language) ? 'en_us' : $default_language,
134 'default_module' => empty($default_module) ? 'Home' : $default_module,
135 'default_password' => empty($default_password) ? '' : $default_password,
136 'default_permissions' => array (
142 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
143 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
144 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
145 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
146 'disable_export' => empty($disable_export) ? false : $disable_export,
147 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
148 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
149 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
150 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
151 'host_name' => empty($host_name) ? 'localhost' : $host_name,
152 'import_dir' => $import_dir, // this must be set!!
153 'import_max_records_per_file' => 100,
154 'import_max_records_total_limit' => '',
155 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
156 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
157 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
158 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
159 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
160 'name_formats' => empty($nameFormats) ? array(
161 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
162 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
164 'portal_view' => 'single_user',
165 'resource_management' => array (
166 'special_query_limit' => 50000,
167 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
168 'default_limit' => 1000,
170 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
171 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
172 'session_dir' => $session_dir, // this must be set!!
173 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
174 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
175 'showThemePicker' => true,
176 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
177 'time_formats' => empty($timeFormats) ? array (
178 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
179 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
180 'tmp_dir' => $tmp_dir, // this must be set!!
181 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
182 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
183 'upload_badext' => empty($upload_badext) ? array (
184 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
185 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
186 'upload_dir' => $upload_dir, // this must be set!!
187 'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
188 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
189 'lock_homepage' => false,
190 'lock_subpanels' => false,
191 'max_dashlets_homepage' => 15,
192 'dashlet_display_row_options' => array('1','3','5','10'),
193 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
194 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
195 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
196 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
197 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
198 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
199 'default_call_status' => 'Planned',
200 'js_lang_version' => 1,
201 'passwordsetting' => empty($passwordsetting) ? array (
202 'SystemGeneratedPasswordON' => '',
203 'generatepasswordtmpl' => '',
204 'lostpasswordtmpl' => '',
205 'forgotpasswordON' => true,
206 'linkexpiration' => '1',
207 'linkexpirationtime' => '30',
208 'linkexpirationtype' => '1',
209 'systexpiration' => '0',
210 'systexpirationtime' => '',
211 'systexpirationtype' => '0',
212 'systexpirationlogin' => '',
213 ) : $passwordsetting,
214 'use_sprites' => function_exists('imagecreatetruecolor'),
215 'search_wildcard_infront' => false,
216 'search_wildcard_char' => '%',
220 function get_sugar_config_defaults() {
223 * used for getting base values for array style config.php. used by the
224 * installer and to fill in new entries on upgrades. see also:
228 $sugar_config_defaults = array (
229 'admin_export_only' => false,
230 'export_delimiter' => ',',
231 'cache_dir' => 'cache/',
232 'calculate_response_time' => true,
233 'create_default_user' => false,
234 'chartEngine' => 'Jit',
235 'date_formats' => array (
236 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
237 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
238 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
239 'name_formats' => array (
240 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
241 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
243 'dbconfigoption' => array (
244 'persistent' => true,
248 'default_action' => 'index',
249 'default_charset' => return_session_value_or_default('default_charset',
251 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
252 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
253 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
254 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
255 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
256 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
257 'default_date_format' => 'm/d/Y',
258 'default_locale_name_format' => 's f l',
259 'default_export_charset' => 'UTF-8',
260 'default_language' => return_session_value_or_default('default_language',
262 'default_module' => 'Home',
263 'default_password' => '',
264 'default_permissions' => array (
270 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
271 'default_time_format' => 'h:ia',
272 'default_user_is_admin' => false,
273 'default_user_name' => '',
274 'disable_export' => false,
275 'disable_persistent_connections' =>
276 return_session_value_or_default('disable_persistent_connections',
278 'display_email_template_variable_chooser' => false,
279 'display_inbound_email_buttons' => false,
280 'dump_slow_queries' => false,
281 'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
282 'email_default_editor' => 'html',
283 'email_default_client' => 'sugar',
284 'email_default_delete_attachments' => true,
285 'history_max_viewed' => 50,
286 'installer_locked' => true,
287 'import_max_records_per_file' => 100,
288 'import_max_records_total_limit' => '',
289 'languages' => array('en_us' => 'English (US)'),
290 'large_scale_test' => false,
291 'list_max_entries_per_page' => 20,
292 'list_max_entries_per_subpanel' => 10,
293 'lock_default_user_name' => false,
294 'log_memory_usage' => false,
295 'portal_view' => 'single_user',
296 'resource_management' => array (
297 'special_query_limit' => 50000,
298 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
299 'default_limit' => 1000,
301 'require_accounts' => true,
302 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
304 'save_query' => 'all',
305 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
306 'showThemePicker' => true,
307 'slow_query_time_msec' => '100',
309 'time_formats' => array (
310 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
311 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
312 'tracker_max_display_length' => 15,
313 'translation_string_prefix' =>
314 return_session_value_or_default('translation_string_prefix', false),
315 'upload_badext' => array (
316 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
317 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
318 'upload_maxsize' => 30000000,
319 'import_max_execution_time' => 3600,
320 // 'use_php_code_json' => returnPhpJsonStatus(),
321 'verify_client_ip' => true,
322 'js_custom_version' => '',
323 'js_lang_version' => 1,
324 'lead_conv_activity_opt' => 'donothing',
325 'default_number_grouping_seperator' => ',',
326 'default_decimal_seperator' => '.',
327 'lock_homepage' => false,
328 'lock_subpanels' => false,
329 'max_dashlets_homepage' => '15',
330 'default_max_tabs' => '7',
331 'dashlet_display_row_options' => array('1','3','5','10'),
332 'default_subpanel_tabs' => true,
333 'default_subpanel_links' => false,
334 'default_swap_last_viewed' => false,
335 'default_swap_shortcuts' => false,
336 'default_navigation_paradigm' => 'gm',
337 'admin_access_control' => false,
338 'use_common_ml_dir' => false,
339 'common_ml_dir' => '',
342 'default_view' => 'week',
343 'show_calls_by_default' => true,
344 'show_tasks_by_default' => true,
345 'editview_width' => 990,
346 'editview_height' => 480,
347 'day_timestep' => 15,
348 'week_timestep' => 30,
349 'month_timestep' => 60,
350 'items_draggable' => true,
351 'mouseover_expand' => true,
353 'passwordsetting' => empty($passwordsetting) ? array (
354 'SystemGeneratedPasswordON' => '',
355 'generatepasswordtmpl' => '',
356 'lostpasswordtmpl' => '',
357 'forgotpasswordON' => false,
358 'linkexpiration' => '1',
359 'linkexpirationtime' => '30',
360 'linkexpirationtype' => '1',
361 'systexpiration' => '0',
362 'systexpirationtime' => '',
363 'systexpirationtype' => '0',
364 'systexpirationlogin' => '',
365 ) : $passwordsetting,
366 'use_real_names' => true,
367 'search_wildcard_infront' => false,
368 'search_wildcard_char' => '%',
371 if(!is_object($locale)) {
372 $locale = new Localization();
375 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
377 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
378 return( $sugar_config_defaults );
382 * @deprecated use SugarView::getMenu() instead
384 function load_menu($path){
387 if(file_exists($path . 'Menu.php'))
389 require($path . 'Menu.php');
391 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
393 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
395 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
397 require('custom/application/Ext/Menus/menu.ext.php');
403 * get_notify_template_file
404 * This function will return the location of the email notifications template to use
406 * @return string relative file path to email notifications template file
408 function get_notify_template_file($language){
410 * Order of operation:
411 * 1) custom version of specified language
412 * 2) stock version of specified language
413 * 3) custom version of en_us template
414 * 4) stock en_us template
417 // set $file to the base code template so it's set if none of the conditions pass
418 $file = "include/language/en_us.notify_template.html";
420 if(file_exists("custom/include/language/{$language}.notify_template.html")){
421 $file = "custom/include/language/{$language}.notify_template.html";
423 else if(file_exists("include/language/{$language}.notify_template.html")){
424 $file = "include/language/{$language}.notify_template.html";
426 else if(file_exists("custom/include/language/en_us.notify_template.html")){
427 $file = "custom/include/language/en_us.notify_template.html";
433 function sugar_config_union( $default, $override ){
434 // a little different then array_merge and array_merge_recursive. we want
435 // the second array to override the first array if the same value exists,
436 // otherwise merge the unique keys. it handles arrays of arrays recursively
437 // might be suitable for a generic array_union
438 if( !is_array( $override ) ){
441 foreach( $default as $key => $value ){
442 if( !array_key_exists($key, $override) ){
443 $override[$key] = $value;
445 else if( is_array( $key ) ){
446 $override[$key] = sugar_config_union( $value, $override[$key] );
452 function make_not_writable( $file ){
453 // Returns true if the given file/dir has been made not writable
455 if( is_file($file) || is_dir($file) ){
456 if( !is_writable($file) ){
460 $original_fileperms = fileperms($file);
462 // take away writable permissions
463 $new_fileperms = $original_fileperms & ~0x0092;
464 @sugar_chmod($file, $new_fileperms);
466 if( !is_writable($file) ){
475 /** This function returns the name of the person.
476 * It currently returns "first last". It should not put the space if either name is not available.
477 * It should not return errors if either name is not available.
478 * If no names are present, it will return ""
479 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
480 * All Rights Reserved.
481 * Contributor(s): ______________________________________..
483 function return_name($row, $first_column, $last_column)
489 if(isset($row[$first_column]))
491 $first_name = stripslashes($row[$first_column]);
494 if(isset($row[$last_column]))
496 $last_name = stripslashes($row[$last_column]);
499 $full_name = $first_name;
501 // If we have a first name and we have a last name
502 if($full_name != "" && $last_name != "")
504 // append a space, then the last name
505 $full_name .= " ".$last_name;
507 // If we have no first name, but we have a last name
508 else if($last_name != "")
510 // append the last name without the space.
511 $full_name .= $last_name;
518 function get_languages()
520 global $sugar_config;
521 $lang = $sugar_config['languages'];
522 if(!empty($sugar_config['disabled_languages'])){
523 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
524 unset($lang[$disable]);
530 function get_all_languages()
532 global $sugar_config;
533 return $sugar_config['languages'];
537 function get_language_display($key)
539 global $sugar_config;
540 return $sugar_config['languages'][$key];
543 function get_assigned_user_name($assigned_user_id, $is_group = '') {
544 static $saved_user_list = null;
546 if(empty($saved_user_list)) {
547 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
550 if(isset($saved_user_list[$assigned_user_id])) {
551 return $saved_user_list[$assigned_user_id];
558 * retrieves the user_name column value (login)
559 * @param string id GUID of user
562 function get_user_name($id) {
566 $db = DBManagerFactory::getInstance();
568 $q = "SELECT user_name FROM users WHERE id='{$id}'";
570 $a = $db->fetchByAssoc($r);
572 return (empty($a)) ? '' : $a['user_name'];
576 //TODO Update to use global cache
580 * This is a helper function to return an Array of users depending on the parameters passed into the function.
581 * This function uses the get_register_value function by default to use a caching layer where supported.
583 * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
584 * @param string $status String value indicating the status to filter users by, "Active" by default
585 * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
586 * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
587 * @param String $user_name_filter String value indicating the user_name filter (searches the user_name column of users table) to optionally search with, blank by default
588 * @param string $portal_filter String query filter for portal users (defaults to searching non-portal users), change to blank if you wish to search for all users including portal users
589 * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
590 * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
592 function get_user_array($add_blank=true, $status="Active", $user_id='', $use_real_name=false, $user_name_filter='', $portal_filter=' AND portal_only=0 ', $from_cache = true) {
594 global $sugar_config;
597 $locale = new Localization();
601 $key_name = $add_blank. $status . $user_id . $use_real_name . $user_name_filter . $portal_filter;
602 $user_array = get_register_value('user_array', $key_name);
605 if(empty($user_array)) {
606 $db = DBManagerFactory::getInstance();
607 $temp_result = Array();
608 // Including deleted users for now.
609 if (empty($status)) {
610 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$portal_filter;
613 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
616 if (!empty($user_name_filter)) {
617 $user_name_filter = $db->quote($user_name_filter);
618 $query .= " AND user_name LIKE '$user_name_filter%' ";
620 if (!empty($user_id)) {
621 $query .= " OR id='{$user_id}'";
623 $query = $query.' ORDER BY user_name ASC';
624 $GLOBALS['log']->debug("get_user_array query: $query");
625 $result = $db->query($query, true, "Error filling in user array: ");
627 if ($add_blank==true) {
628 // Add in a blank row
629 $temp_result[''] = '';
632 // Get the id and the name.
633 while($row = $db->fetchByAssoc($result)) {
634 if($use_real_name == true || showFullName()) {
635 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
636 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
638 $temp_result[$row['id']] = $row['user_name'];
641 $temp_result[$row['id']] = $row['user_name'];
645 $user_array = $temp_result;
648 set_register_value('user_array', $key_name, $temp_result);
658 * uses a different query to return a list of users than get_user_array()
659 * Used from QuickSearch.php
660 * @param args string where clause entry
661 * @return array Array of Users' details that match passed criteria
663 function getUserArrayFromFullName($args, $hide_portal_users = false) {
665 $db = DBManagerFactory::getInstance();
667 // jmorais@dri - Bug #51411
669 // Refactor the code responsible for parsing supplied $args, this way we
670 // ensure that if $args has at least one space (after trim), the $inClause
671 // will be composed by several clauses ($inClauses) inside parenthesis.
673 // Ensuring that operator precedence is respected, and avoiding
674 // inactive/deleted users to be retrieved.
677 if (strpos($args, ' ')) {
678 $inClauses = array();
680 $argArray = explode(' ', $args);
681 foreach ($argArray as $arg) {
682 $arg = $db->quote($arg);
683 $inClauses[] = "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
686 $inClause = '(' . implode('OR ', $inClauses) . ')';
689 $args = $db->quote($args);
690 $inClause = "(first_name LIKE '{$args}%' OR last_name LIKE '{$args}%')";
694 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
695 if ( $hide_portal_users ) {
696 $query .= " portal_only=0 AND ";
699 $query .= " ORDER BY last_name ASC";
701 $r = $db->query($query);
703 while($a = $db->fetchByAssoc($r)) {
704 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
712 * based on user pref then system pref
714 function showFullName() {
715 global $sugar_config;
716 global $current_user;
717 static $showFullName = null;
719 if (is_null($showFullName)) {
720 $sysPref = !empty($sugar_config['use_real_names']);
721 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
723 if($userPref != null) {
724 $showFullName = ($userPref == 'on');
726 $showFullName = $sysPref;
730 return $showFullName;
733 function clean($string, $maxLength)
735 $string = substr($string, 0, $maxLength);
736 return escapeshellcmd($string);
740 * Copy the specified request variable to the member variable of the specified object.
741 * Do no copy if the member variable is already set.
742 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
743 * All Rights Reserved.
744 * Contributor(s): ______________________________________..
746 function safe_map($request_var, & $focus, $always_copy = false)
748 safe_map_named($request_var, $focus, $request_var, $always_copy);
752 * Copy the specified request variable to the member variable of the specified object.
753 * Do no copy if the member variable is already set.
754 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
755 * All Rights Reserved.
756 * Contributor(s): ______________________________________..
758 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
760 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
761 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
762 $focus->$member_var = $_REQUEST[$request_var];
767 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
769 * @param string $language specific language to load
770 * @return array lang strings
772 function return_app_list_strings_language($language)
774 global $app_list_strings;
775 global $sugar_config;
777 $cache_key = 'app_list_strings.'.$language;
779 // Check for cached value
780 $cache_entry = sugar_cache_retrieve($cache_key);
781 if(!empty($cache_entry))
786 $default_language = $sugar_config['default_language'];
787 $temp_app_list_strings = $app_list_strings;
790 if ($language != 'en_us') {
793 if ($default_language != 'en_us' && $language != $default_language) {
794 $langs[] = $default_language;
796 $langs[] = $language;
798 $app_list_strings_array = array();
800 foreach ( $langs as $lang ) {
801 $app_list_strings = array();
802 if(file_exists("include/language/$lang.lang.php")) {
803 include("include/language/$lang.lang.php");
804 $GLOBALS['log']->info("Found language file: $lang.lang.php");
806 if(file_exists("include/language/$lang.lang.override.php")) {
807 include("include/language/$lang.lang.override.php");
808 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
810 if(file_exists("include/language/$lang.lang.php.override")) {
811 include("include/language/$lang.lang.php.override");
812 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
815 $app_list_strings_array[] = $app_list_strings;
818 $app_list_strings = array();
819 foreach ( $app_list_strings_array as $app_list_strings_item ) {
820 $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
823 foreach ( $langs as $lang ) {
824 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
825 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
826 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
828 if(file_exists("custom/include/language/$lang.lang.php")) {
829 include("custom/include/language/$lang.lang.php");
830 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
834 if(!isset($app_list_strings)) {
835 $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");
839 $return_value = $app_list_strings;
840 $app_list_strings = $temp_app_list_strings;
842 sugar_cache_put($cache_key, $return_value);
844 return $return_value;
848 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
849 * $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.
850 * @param file string the language that you want include,
851 * @param app_list_strings array the golbal strings
855 function _mergeCustomAppListStrings($file , $app_list_strings){
856 $app_list_strings_original = $app_list_strings;
857 unset($app_list_strings);
858 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
859 // This way, language file can add items to save specific standard codelist from being overwritten
860 $exemptDropdowns = array();
862 if(!isset($app_list_strings) || !is_array($app_list_strings)){
863 return $app_list_strings_original;
865 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
867 // FG - bug 45525 - Specific codelists must NOT be overwritten
868 $exemptDropdowns[] = "moduleList";
869 $exemptDropdowns[] = "parent_type_display";
870 $exemptDropdowns[] = "record_type_display";
871 $exemptDropdowns[] = "record_type_display_notes";
873 foreach($app_list_strings as $key=>$value)
875 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
877 unset($app_list_strings_original["$key"]);
880 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
881 return $app_list_strings;
885 * This function retrieves an application language file and returns the array of strings included.
887 * @param string $language specific language to load
888 * @return array lang strings
890 function return_application_language($language)
892 global $app_strings, $sugar_config;
894 $cache_key = 'app_strings.'.$language;
896 // Check for cached value
897 $cache_entry = sugar_cache_retrieve($cache_key);
898 if(!empty($cache_entry))
903 $temp_app_strings = $app_strings;
904 $default_language = $sugar_config['default_language'];
907 if ($language != 'en_us') {
910 if ($default_language != 'en_us' && $language != $default_language) {
911 $langs[] = $default_language;
914 $langs[] = $language;
916 $app_strings_array = array();
918 foreach ( $langs as $lang ) {
919 $app_strings = array();
920 if(file_exists("include/language/$lang.lang.php")) {
921 include("include/language/$lang.lang.php");
922 $GLOBALS['log']->info("Found language file: $lang.lang.php");
924 if(file_exists("include/language/$lang.lang.override.php")) {
925 include("include/language/$lang.lang.override.php");
926 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
928 if(file_exists("include/language/$lang.lang.php.override")) {
929 include("include/language/$lang.lang.php.override");
930 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
932 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
933 include("custom/application/Ext/Language/$lang.lang.ext.php");
934 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
936 if(file_exists("custom/include/language/$lang.lang.php")) {
937 include("custom/include/language/$lang.lang.php");
938 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
940 $app_strings_array[] = $app_strings;
943 $app_strings = array();
944 foreach ( $app_strings_array as $app_strings_item ) {
945 $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
948 if(!isset($app_strings)) {
949 $GLOBALS['log']->fatal("Unable to load the application language strings");
953 // If we are in debug mode for translating, turn on the prefix now!
954 if($sugar_config['translation_string_prefix']) {
955 foreach($app_strings as $entry_key=>$entry_value) {
956 $app_strings[$entry_key] = $language.' '.$entry_value;
959 if(isset($_SESSION['show_deleted'])) {
960 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
961 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
962 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
963 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
966 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
968 $return_value = $app_strings;
969 $app_strings = $temp_app_strings;
971 sugar_cache_put($cache_key, $return_value);
973 return $return_value;
977 * This function retrieves a module's language file and returns the array of strings included.
979 * @param string $language specific language to load
980 * @param string $module module name to load strings for
981 * @param bool $refresh optional, true if you want to rebuild the language strings
982 * @return array lang strings
984 function return_module_language($language, $module, $refresh=false)
987 global $sugar_config;
988 global $currentModule;
990 // Jenny - Bug 8119: Need to check if $module is not empty
991 if (empty($module)) {
992 $stack = debug_backtrace();
993 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
999 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1000 // Check for cached value
1001 $cache_entry = sugar_cache_retrieve($cache_key);
1002 if(!empty($cache_entry))
1004 return $cache_entry;
1007 // Store the current mod strings for later
1008 $temp_mod_strings = $mod_strings;
1009 $loaded_mod_strings = array();
1010 $language_used = $language;
1011 $default_language = $sugar_config['default_language'];
1013 if(empty($language)) {
1014 $language = $default_language;
1017 // Bug 21559 - So we can get all the strings defined in the template, refresh
1018 // the vardefs file if the cached language file doesn't exist.
1019 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1020 && !empty($GLOBALS['beanList'][$module])){
1021 $object = BeanFactory::getObjectName($module);
1022 VardefManager::refreshVardefs($module,$object);
1025 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1027 // cn: bug 6048 - merge en_us with requested language
1028 if($language != $sugar_config['default_language'])
1029 $loaded_mod_strings = sugarArrayMerge(
1030 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1034 // Load in en_us strings by default
1035 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1036 $loaded_mod_strings = sugarArrayMerge(
1037 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1041 // If we are in debug mode for translating, turn on the prefix now!
1042 if($sugar_config['translation_string_prefix']) {
1043 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1044 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1048 $return_value = $loaded_mod_strings;
1049 if(!isset($mod_strings)){
1050 $mod_strings = $return_value;
1053 $mod_strings = $temp_mod_strings;
1055 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1056 sugar_cache_put($cache_key, $return_value);
1057 return $return_value;
1061 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1062 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1063 * All Rights Reserved.
1064 * Contributor(s): ______________________________________..
1065 * If you are using the current language, do not call this function unless you are loading it for the first time */
1066 function return_mod_list_strings_language($language,$module) {
1067 global $mod_list_strings;
1068 global $sugar_config;
1069 global $currentModule;
1071 $cache_key = "mod_list_str_lang.".$language.$module;
1073 // Check for cached value
1074 $cache_entry = sugar_cache_retrieve($cache_key);
1075 if(!empty($cache_entry))
1077 return $cache_entry;
1080 $language_used = $language;
1081 $temp_mod_list_strings = $mod_list_strings;
1082 $default_language = $sugar_config['default_language'];
1084 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1085 return $mod_list_strings;
1088 // cn: bug 6351 - include en_us if file langpack not available
1089 // cn: bug 6048 - merge en_us with requested language
1090 include("modules/$module/language/en_us.lang.php");
1091 $en_mod_list_strings = array();
1092 if($language_used != $default_language)
1093 $en_mod_list_strings = $mod_list_strings;
1095 if(file_exists("modules/$module/language/$language.lang.php")) {
1096 include("modules/$module/language/$language.lang.php");
1099 if(file_exists("modules/$module/language/$language.lang.override.php")){
1100 include("modules/$module/language/$language.lang.override.php");
1103 if(file_exists("modules/$module/language/$language.lang.php.override")){
1104 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1105 include("modules/$module/language/$language.lang.php.override");
1108 // cn: bug 6048 - merge en_us with requested language
1109 $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1111 // if we still don't have a language pack, then log an error
1112 if(!isset($mod_list_strings)) {
1113 $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})");
1117 $return_value = $mod_list_strings;
1118 $mod_list_strings = $temp_mod_list_strings;
1120 sugar_cache_put($cache_key, $return_value);
1121 return $return_value;
1125 /** This function retrieves a theme's language file and returns the array of strings included.
1126 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1127 * All Rights Reserved.
1128 * Contributor(s): ______________________________________..
1130 function return_theme_language($language, $theme)
1132 global $mod_strings, $sugar_config, $current_language;
1134 $language_used = $language;
1135 $default_language = $sugar_config['default_language'];
1137 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1138 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1139 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1141 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1142 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";
1143 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1145 if(!isset($theme_strings))
1147 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1148 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1149 $language_used = $default_language;
1152 if(!isset($theme_strings))
1154 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1158 // If we are in debug mode for translating, turn on the prefix now!
1159 if($sugar_config['translation_string_prefix'])
1161 foreach($theme_strings as $entry_key=>$entry_value)
1163 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1167 return $theme_strings;
1172 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1173 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1174 * All Rights Reserved.
1175 * Contributor(s): ______________________________________..
1177 function return_session_value_or_default($varname, $default)
1179 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1181 return $_SESSION[$varname];
1188 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1189 * 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.
1190 * @param &$where_clauses - The array to append the clause to
1191 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1192 * @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.
1193 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1194 * All Rights Reserved.
1195 * Contributor(s): ______________________________________..
1197 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1199 if($SQL_name == null)
1201 $SQL_name = $variable_name;
1204 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1206 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1211 * Generate the appropriate SQL based on the where clauses.
1212 * @param $where_clauses - An Array of individual where clauses stored as strings
1213 * @returns string where_clause - The final SQL where clause to be executed.
1214 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1215 * All Rights Reserved.
1216 * Contributor(s): ______________________________________..
1218 function generate_where_statement($where_clauses)
1221 foreach($where_clauses as $clause)
1228 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1233 * determines if a passed string matches the criteria for a Sugar GUID
1234 * @param string $guid
1235 * @return bool False on failure
1237 function is_guid($guid) {
1238 if(strlen($guid) != 36) {
1242 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1251 * A temporary method of generating GUIDs of the correct format for our DB.
1252 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1254 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1255 * All Rights Reserved.
1256 * Contributor(s): ______________________________________..
1258 function create_guid()
1260 $microTime = microtime();
1261 list($a_dec, $a_sec) = explode(" ", $microTime);
1263 $dec_hex = dechex($a_dec* 1000000);
1264 $sec_hex = dechex($a_sec);
1266 ensure_length($dec_hex, 5);
1267 ensure_length($sec_hex, 6);
1271 $guid .= create_guid_section(3);
1273 $guid .= create_guid_section(4);
1275 $guid .= create_guid_section(4);
1277 $guid .= create_guid_section(4);
1280 $guid .= create_guid_section(6);
1286 function create_guid_section($characters)
1289 for($i=0; $i<$characters; $i++)
1291 $return .= dechex(mt_rand(0,15));
1296 function ensure_length(&$string, $length)
1298 $strlen = strlen($string);
1299 if($strlen < $length)
1301 $string = str_pad($string,$length,"0");
1303 else if($strlen > $length)
1305 $string = substr($string, 0, $length);
1309 function microtime_diff($a, $b) {
1310 list($a_dec, $a_sec) = explode(" ", $a);
1311 list($b_dec, $b_sec) = explode(" ", $b);
1312 return $b_sec - $a_sec + $b_dec - $a_dec;
1315 // check if Studio is displayed.
1316 function displayStudioForCurrentUser()
1318 global $current_user;
1319 if ( $current_user->isAdmin() ) {
1329 function displayWorkflowForCurrentUser()
1331 $_SESSION['display_workflow_for_user'] = false;
1335 // return an array with all modules where the user is an admin.
1336 function get_admin_modules_for_user($user) {
1337 $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");
1344 return($user->getDeveloperModules());
1348 function get_workflow_admin_modules_for_user($user){
1349 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1350 return $_SESSION['get_workflow_admin_modules_for_user'];
1354 $workflow_mod_list = array();
1355 foreach($moduleList as $module){
1356 $workflow_mod_list[$module] = $module;
1359 // This list is taken from teh previous version of workflow_utils.php
1360 $workflow_mod_list['Tasks'] = "Tasks";
1361 $workflow_mod_list['Calls'] = "Calls";
1362 $workflow_mod_list['Meetings'] = "Meetings";
1363 $workflow_mod_list['Notes'] = "Notes";
1364 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1365 $workflow_mod_list['Leads'] = "Leads";
1366 $workflow_mod_list['Opportunities'] = "Opportunities";
1369 $workflow_admin_modules = array();
1371 return $workflow_admin_modules;
1373 $actions = ACLAction::getUserActions($user->id);
1374 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1375 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1376 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1377 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1379 foreach ($workflow_mod_list as $key=>$val) {
1380 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1381 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1382 ($user->isDeveloperForModule($key))) {
1383 $workflow_admin_modules[$key] = $val;
1386 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1387 return ($workflow_admin_modules);
1390 // Check if user is admin for at least one module.
1391 function is_admin_for_any_module($user) {
1395 if($user->isAdmin()) {
1402 // Check if user is admin for a specific module.
1403 function is_admin_for_module($user,$module) {
1404 if (!isset($user)) {
1407 if ($user->isAdmin()) {
1415 * Check if user id belongs to a system admin.
1416 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1417 * All Rights Reserved.
1418 * Contributor(s): ______________________________________..
1420 function is_admin($user) {
1425 return $user->isAdmin();
1429 * Return the display name for a theme if it exists.
1430 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1431 * All Rights Reserved.
1432 * Contributor(s): ______________________________________..
1434 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1436 function get_theme_display($theme)
1438 return SugarThemeRegistry::get($theme)->name;
1442 * Return an array of directory names.
1443 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1444 * All Rights Reserved.
1445 * Contributor(s): ______________________________________..
1447 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1449 function get_themes()
1451 return SugarThemeRegistry::availableThemes();
1455 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1456 * Create HTML to display select options in a dropdown list. To be used inside
1457 * of a select statement in a form.
1458 * param $option_list - the array of strings to that contains the option list
1459 * param $selected - the string which contains the default value
1460 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1461 * All Rights Reserved.
1462 * Contributor(s): ______________________________________..
1464 function get_select_options ($option_list, $selected) {
1465 return get_select_options_with_id($option_list, $selected);
1469 * Create HTML to display select options in a dropdown list. To be used inside
1470 * 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.
1471 * param $option_list - the array of strings to that contains the option list
1472 * param $selected - the string which contains the default value
1473 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1474 * All Rights Reserved.
1475 * Contributor(s): ______________________________________..
1477 function get_select_options_with_id ($option_list, $selected_key) {
1478 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1483 * Create HTML to display select options in a dropdown list. To be used inside
1484 * 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.
1485 * param $label_list - the array of strings to that contains the option list
1486 * param $key_list - the array of strings to that contains the values list
1487 * param $selected - the string which contains the default value
1488 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1489 * All Rights Reserved.
1490 * Contributor(s): ______________________________________..
1492 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1493 global $app_strings;
1494 $select_options = "";
1496 //for setting null selection values to human readable --None--
1497 $pattern = "/'0?'></";
1498 $replacement = "''>".$app_strings['LBL_NONE']."<";
1500 $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
1503 if (empty($key_list)) $key_list = array();
1504 //create the type dropdown domain and set the selected value if $opp value already exists
1505 foreach ($key_list as $option_key=>$option_value) {
1507 $selected_string = '';
1508 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1509 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1510 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1512 $selected_string = 'selected ';
1515 $html_value = $option_key;
1517 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1519 $select_options = preg_replace($pattern, $replacement, $select_options);
1520 return $select_options;
1525 * Call this method instead of die().
1526 * Then we call the die method with the error message that is passed in.
1528 function sugar_die($error_message)
1532 die($error_message);
1537 * Create javascript to clear values of all elements in a form.
1538 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1539 * All Rights Reserved.
1540 * Contributor(s): ______________________________________..
1542 function get_clear_form_js () {
1543 $the_script = <<<EOQ
1544 <script type="text/javascript" language="JavaScript">
1545 function clear_form(form) {
1546 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1547 if(typeof(form.advanced) != 'undefined'){
1548 newLoc += '&advanced=' + form.advanced.value;
1550 document.location.href= newLoc;
1559 * Create javascript to set the cursor focus to specific field in a form
1560 * when the screen is rendered. The field name is currently hardcoded into the
1562 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1563 * All Rights Reserved.
1564 * Contributor(s): ______________________________________..
1566 function get_set_focus_js () {
1567 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1568 $the_script = <<<EOQ
1569 <script type="text/javascript" language="JavaScript">
1571 function set_focus() {
1572 if (document.forms.length > 0) {
1573 for (i = 0; i < document.forms.length; i++) {
1574 for (j = 0; j < document.forms[i].elements.length; j++) {
1575 var field = document.forms[i].elements[j];
1576 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1577 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1579 if (field.type == "text") {
1596 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1597 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1598 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1599 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1600 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1601 * the first - so the array is sorted by the last given column first, then the one before ...
1602 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1603 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1604 * All Rights Reserved.
1605 * Contributor(s): ______________________________________..
1607 function array_csort() {
1608 $args = func_get_args();
1609 $marray = array_shift($args);
1612 $msortline = "return(array_multisort(";
1613 foreach ($args as $arg) {
1615 if (is_string($arg)) {
1616 foreach ($marray as $row) {
1617 $sortarr[$i][] = $row[$arg];
1620 $sortarr[$i] = $arg;
1622 $msortline .= "\$sortarr[".$i."],";
1624 $msortline .= "\$marray));";
1631 * Converts localized date format string to jscalendar format
1632 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1633 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1634 * All Rights Reserved.
1635 * Contributor(s): ______________________________________..
1637 function parse_calendardate($local_format) {
1638 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1639 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1640 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1647 function translate($string, $mod='', $selectedValue=''){
1648 //$test_start = microtime();
1649 //static $mod_strings_results = array();
1651 global $current_language;
1653 if(isset($_REQUEST['login_language'])){
1654 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1656 $mod_strings = return_module_language($current_language, $mod);
1659 global $mod_strings;
1663 global $app_strings, $app_list_strings;
1665 if(isset($mod_strings[$string]))
1666 $returnValue = $mod_strings[$string];
1667 else if(isset($app_strings[$string]))
1668 $returnValue = $app_strings[$string];
1669 else if(isset($app_list_strings[$string]))
1670 $returnValue = $app_list_strings[$string];
1671 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1672 $returnValue = $app_list_strings['moduleList'][$string];
1675 //$test_end = microtime();
1677 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1679 // echo("translate results:");
1681 // $total_strings = 0;
1682 // foreach($mod_strings_results as $key=>$value)
1684 // echo("Module $key \t\t time $value \t\t<br>");
1685 // $total_time += $value;
1688 // echo("Total time: $total_time<br>");
1692 if(empty($returnValue)){
1696 // Bug 48996 - Custom enums with '0' value were not returning because of empty check
1697 // Added a numeric 0 checker to the conditional to allow 0 value indexed to pass
1698 if(is_array($returnValue) && (!empty($selectedValue) || (is_numeric($selectedValue) && $selectedValue == 0)) && isset($returnValue[$selectedValue]) ){
1699 return $returnValue[$selectedValue];
1702 return $returnValue;
1705 function unTranslateNum($num) {
1707 static $num_grp_sep;
1708 global $current_user, $sugar_config;
1710 if($dec_sep == null) {
1711 $user_dec_sep = $current_user->getPreference('dec_sep');
1712 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1714 if($num_grp_sep == null) {
1715 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1716 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1719 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1720 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1725 function add_http($url) {
1726 if(!preg_match("@://@i", $url)) {
1728 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1732 return "{$scheme}://{$url}";
1739 * returns a default array of XSS tags to clean
1742 function getDefaultXssTags() {
1744 "applet" => "applet",
1749 "frameset" => "frameset",
1750 "iframe" => "iframe",
1751 "import" => "\?import",
1754 "object" => "object",
1755 "script" => "script",
1759 $ret = base64_encode(serialize($tmp));
1765 * Remove potential xss vectors from strings
1766 * @param string str String to search for XSS attack vectors
1767 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1770 function remove_xss($str, $cleanImg=true)
1772 $potentials = clean_xss($str, $cleanImg);
1773 if(is_array($potentials) && !empty($potentials)) {
1774 foreach($potentials as $bad) {
1775 $str = str_replace($bad, "", $str);
1782 * Detects typical XSS attack patterns
1783 * @param string str String to search for XSS attack vectors
1784 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1785 * @return array Array of matches, empty on clean string
1787 function clean_xss($str, $cleanImg=true) {
1788 global $sugar_config;
1790 if(empty($sugar_config['email_xss']))
1791 $sugar_config['email_xss'] = getDefaultXssTags();
1793 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1795 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1796 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1797 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1798 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1800 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1801 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1802 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1803 $css_url = '#url\(.*\.\w+\)#';
1805 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1807 $tagmatches = array();
1809 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1810 foreach($tagmatches[1] as $no => $tag) {
1811 if(in_array($tag, $xsstags)) {
1812 // dangerous tag - take out whole
1813 $matches[] = $tagmatches[0][$no];
1816 $attrmatch = array();
1817 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1818 if(!empty($attrmatch[0])) {
1819 $matches = array_merge($matches, $attrmatch[0]);
1823 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1826 $matches = array_merge($matches,
1827 xss_check_pattern($imgsrc_regex, $str)
1831 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1832 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1834 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1835 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1836 // normalize whitelist
1837 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1838 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1841 foreach($cssUrlMatches[0] as $match) {
1842 $domain = strtolower(substr(strstr($match, "://"), 3));
1843 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1845 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1846 $matches[] = $match;
1851 $matches = array_merge($matches, $cssUrlMatches[0]);
1858 * Helper function used by clean_xss() to parse for known-bad vectors
1859 * @param string pattern Regex pattern to use
1860 * @param string str String to parse for badness
1863 function xss_check_pattern($pattern, $str) {
1864 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1869 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1871 * @param string $str
1872 * @param string $filter which corresponds to a regular expression to use; choices are:
1873 * "STANDARD" ( default )
1883 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1885 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1887 global $sugar_config;
1890 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1891 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1892 "FILE" => '#[^A-Z0-9\-_\.]#i',
1893 "NUMBER" => '#[^0-9\-]#i',
1894 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1895 "PATH_NO_URL" => '#://#i',
1896 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1897 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1898 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1899 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1902 if (preg_match($filters[$filter], $str)) {
1903 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1904 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1906 if ( $dieOnBadData ) {
1907 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1916 function clean_special_arguments() {
1917 if(isset($_SERVER['PHP_SELF'])) {
1918 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1920 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1921 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1922 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1923 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1924 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1925 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1926 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1927 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1928 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1929 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1930 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1931 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1932 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1933 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1934 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1935 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1936 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1937 clean_superglobals('offset', 'ALPHANUM');
1938 clean_superglobals('return_action');
1939 clean_superglobals('return_module');
1944 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1946 function clean_superglobals($key, $filter = 'STANDARD') {
1947 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1948 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1949 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1952 function set_superglobals($key, $val){
1954 $_POST[$key] = $val;
1955 $_REQUEST[$key] = $val;
1958 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1959 function clean_incoming_data() {
1960 global $sugar_config;
1961 global $RAW_REQUEST;
1963 if(get_magic_quotes_gpc()) {
1964 // magic quotes screw up data, we'd have to clean up
1965 $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1967 $RAW_REQUEST = $_REQUEST;
1970 if (get_magic_quotes_gpc() == 1) {
1971 $req = array_map("preprocess_param", $_REQUEST);
1972 $post = array_map("preprocess_param", $_POST);
1973 $get = array_map("preprocess_param", $_GET);
1976 $req = array_map("securexss", $_REQUEST);
1977 $post = array_map("securexss", $_POST);
1978 $get = array_map("securexss", $_GET);
1981 // PHP cannot stomp out superglobals reliably
1982 foreach($post as $k => $v) { $_POST[$k] = $v; }
1983 foreach($get as $k => $v) { $_GET[$k] = $v; }
1984 foreach($req as $k => $v) {
1987 //ensure the keys are safe as well. If mbstring encoding translation is on, the post keys don't
1988 //get translated, so scrub the data but don't die
1989 if(ini_get('mbstring.encoding_translation')==='1'){
1990 securexsskey($k,false);
1992 securexsskey($k,true);
1996 // Any additional variables that need to be cleaned should be added here
1997 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1998 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1999 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
2000 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
2001 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
2002 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
2003 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
2004 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
2005 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
2006 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
2007 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
2008 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
2009 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
2011 if(isset($_REQUEST['lvso'])){
2012 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
2014 // Clean "offset" and "order_by" parameters in URL
2015 foreach ($_REQUEST as $key => $val) {
2016 if (str_end($key, "_offset")) {
2017 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
2018 set_superglobals($key, $_REQUEST[$key]);
2020 elseif (str_end($key, "_ORDER_BY")) {
2021 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2022 set_superglobals($key, $_REQUEST[$key]);
2030 // Returns TRUE if $str begins with $begin
2031 function str_begin($str, $begin) {
2032 return (substr($str, 0, strlen($begin)) == $begin);
2035 // Returns TRUE if $str ends with $end
2036 function str_end($str, $end) {
2037 return (substr($str, strlen($str) - strlen($end)) == $end);
2040 function securexss($value) {
2041 if(is_array($value)){
2043 foreach($value as $key=>$val){
2044 $new[$key] = securexss($val);
2048 static $xss_cleanup= array(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2049 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2050 $value = preg_replace('/javascript:/i', 'java script:', $value);
2051 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2054 function securexsskey($value, $die=true){
2055 global $sugar_config;
2057 preg_match('/[\'"<>]/', $value, $matches);
2058 if(!empty($matches)){
2060 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2062 unset($_REQUEST[$value]);
2063 unset($_POST[$value]);
2064 unset($_GET[$value]);
2069 function preprocess_param($value){
2070 if(is_string($value)){
2071 if(get_magic_quotes_gpc() == 1){
2072 $value = stripslashes($value);
2075 $value = securexss($value);
2081 function cleanup_slashes($value)
2083 if(is_string($value)) return stripslashes($value);
2088 function set_register_value($category, $name, $value){
2089 return sugar_cache_put("{$category}:{$name}", $value);
2092 function get_register_value($category,$name){
2093 return sugar_cache_retrieve("{$category}:{$name}");
2096 function clear_register_value($category,$name){
2097 return sugar_cache_clear("{$category}:{$name}");
2099 // this function cleans id's when being imported
2100 function convert_id($string)
2102 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2104 // single quotes are essential here,
2105 // or alternative escape all $ as \$
2107 'return ord($matches[0]);'
2112 * @deprecated use SugarTheme::getImage()
2114 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2116 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2119 * @deprecated use SugarTheme::getImageURL()
2121 function getImagePath($image_name)
2123 return SugarThemeRegistry::current()->getImageURL($image_name);
2126 function getWebPath($relative_path){
2127 //if it has a :// then it isn't a relative path
2128 if(substr_count($relative_path, '://') > 0) return $relative_path;
2129 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2130 return $relative_path;
2133 function getVersionedPath($path, $additional_attrs='')
2135 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2136 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2137 if(inDeveloperMode()) {
2139 if(empty($rand)) $rand = mt_rand();
2144 if(is_array($additional_attrs)) {
2145 $additional_attrs = join("|",$additional_attrs);
2147 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2148 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2149 // remove / - it confuses some parsers
2150 $str = strtr($str, '/+', '-_');
2151 if(empty($path)) return $str;
2153 return $path . "?v=$str";
2156 function getVersionedScript($path, $additional_attrs='')
2158 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2161 function getJSPath($relative_path, $additional_attrs='')
2163 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2164 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2167 function getSWFPath($relative_path, $additional_params=''){
2168 $path = $relative_path;
2169 if (!empty($additional_params)){
2170 $path .= '?' . $additional_params;
2172 if (defined('TEMPLATE_URL')){
2173 $path = TEMPLATE_URL . '/' . $path;
2182 function getSQLDate($date_str)
2184 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2186 if ( strlen($match[2]) == 1)
2188 $match[2] = "0".$match[2];
2190 if ( strlen($match[1]) == 1)
2192 $match[1] = "0".$match[1];
2194 return "{$match[3]}-{$match[1]}-{$match[2]}";
2196 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2198 if ( strlen($match[2]) == 1)
2200 $match[2] = "0".$match[2];
2202 if ( strlen($match[1]) == 1)
2204 $match[1] = "0".$match[1];
2206 return "{$match[3]}-{$match[1]}-{$match[2]}";
2214 function clone_history(&$db, $from_id,$to_id, $to_type)
2219 require_once('include/upload_file.php');
2220 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2222 $location=array('Email'=>"modules/Emails/Email.php",
2223 'Call'=>"modules/Calls/Call.php",
2224 'Meeting'=>"modules/Meetings/Meeting.php",
2225 'Note'=>"modules/Notes/Note.php",
2226 'Tasks'=>"modules/Tasks/Task.php",
2230 foreach($tables as $table=>$bean_class)
2233 if (!class_exists($bean_class))
2235 require_once($location[$bean_class]);
2238 $bProcessingNotes=false;
2239 if ($table=='notes')
2241 $bProcessingNotes=true;
2243 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2244 $results = $db->query($query);
2245 while($row = $db->fetchByAssoc($results))
2247 //retrieve existing record.
2248 $bean= new $bean_class();
2249 $bean->retrieve($row['id']);
2250 //process for new instance.
2251 if ($bProcessingNotes)
2253 $old_note_id=$row['id'];
2254 $old_filename=$bean->filename;
2257 $bean->parent_id=$to_id;
2258 $bean->parent_type=$to_type;
2259 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2261 $bean->contact_id=$to_id;
2263 $bean->update_date_modified = false;
2264 $bean->update_modified_by = false;
2265 if(isset($bean->date_modified))
2266 $bean->date_modified = $timedate->to_db($bean->date_modified);
2267 if(isset($bean->date_entered))
2268 $bean->date_entered = $timedate->to_db($bean->date_entered);
2270 $new_id=$bean->save();
2272 //duplicate the file now. for notes.
2273 if ($bProcessingNotes && !empty($old_filename))
2275 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2277 //reset the values needed for attachment duplication.
2284 function values_to_keys($array)
2286 $new_array = array();
2287 if(!is_array($array))
2291 foreach($array as $arr){
2292 $new_array[$arr] = $arr;
2297 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2299 foreach($tables as $table)
2302 if ($table == 'emails_beans') {
2303 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2305 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2307 $results = $db->query($query);
2308 while($row = $db->fetchByAssoc($results))
2310 $query = "INSERT INTO $table ";
2313 $row[$from_column] = $to_id;
2314 $row['id'] = create_guid();
2315 if ($table=='emails_beans') {
2316 $row['bean_module'] =='Contacts';
2319 foreach($row as $name=>$value)
2325 $values .= "'$value'";
2328 $names .= ', '. $name;
2329 $values .= ", '$value'";
2332 $query .= "($names) VALUES ($values)";
2338 function get_unlinked_email_query($type, $bean) {
2339 global $current_user;
2341 $return_array['select']='SELECT emails.id ';
2342 $return_array['from']='FROM emails ';
2343 $return_array['where']="";
2344 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2346 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2347 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2348 where eear.deleted=0 and eear.email_id not in
2349 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2350 ) derivedemails on derivedemails.email_id = emails.id";
2351 $return_array['join_tables'][0] = '';
2353 if (isset($type) and !empty($type['return_as_array'])) {
2354 return $return_array;
2357 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2361 * Check to see if the number is empty or non-zero
2365 function number_empty($value)
2367 return empty($value) && $value != '0';
2370 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2373 require_once($beanFiles[$bean_name]);
2374 $focus = new $bean_name();
2375 $user_array = array();
2377 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2378 $user_array = get_register_value('select_array', $key );
2382 $db = DBManagerFactory::getInstance();
2384 $temp_result = Array();
2385 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2389 $query .= $where." AND ";
2392 $query .= " {$focus->table_name}.deleted=0";
2394 if ( $order_by != '')
2396 $query .= " order by {$focus->table_name}.{$order_by}";
2399 $GLOBALS['log']->debug("get_user_array query: $query");
2400 $result = $db->query($query, true, "Error filling in user array: ");
2402 if ($add_blank==true){
2403 // Add in a blank row
2404 if($blank_is_none == true) { // set 'blank row' to "--None--"
2405 global $app_strings;
2406 $temp_result[''] = $app_strings['LBL_NONE'];
2408 $temp_result[''] = '';
2412 // Get the id and the name.
2413 while($row = $db->fetchByAssoc($result))
2415 $temp_result[$row['id']] = $row['display'];
2418 $user_array = $temp_result;
2419 set_register_value('select_array', $key ,$temp_result);
2428 * @param unknown_type $listArray
2430 // function parse_list_modules
2431 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2432 function parse_list_modules(&$listArray)
2434 global $modListHeader;
2435 $returnArray = array();
2437 foreach($listArray as $optionName => $optionVal)
2439 if(array_key_exists($optionName, $modListHeader))
2441 $returnArray[$optionName] = $optionVal;
2444 // special case for projects
2445 if(array_key_exists('Project', $modListHeader))
2447 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2450 $acldenied = ACLController::disabledModuleList($listArray,false);
2451 foreach($acldenied as $denied){
2452 unset($returnArray[$denied]);
2454 asort($returnArray);
2456 return $returnArray;
2459 function display_notice($msg = false){
2460 global $error_notice;
2461 //no error notice - lets just display the error to the user
2462 if(!isset($error_notice)){
2463 echo '<br>'.$msg . '<br>';
2465 $error_notice .= $msg . '<br>';
2469 /* checks if it is a number that atleast has the plus at the beggining
2471 function skype_formatted($number){
2472 //kbrill - BUG #15375
2473 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2476 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2478 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2481 function format_skype($number) {
2482 return preg_replace('/[^\+0-9]/','',$number);
2485 function insert_charset_header() {
2486 header('Content-Type: text/html; charset=UTF-8');
2489 function getCurrentURL()
2492 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2497 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2501 function javascript_escape($str) {
2504 for($i = 0; $i < strlen($str); $i++) {
2506 if(ord(substr($str, $i, 1))==10){
2508 }elseif(ord(substr($str, $i, 1))==13){
2512 $new_str .= $str{$i};
2516 $new_str = str_replace("'", "\\'", $new_str);
2521 function js_escape($str, $keep=true){
2522 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2525 $str = javascript_escape($str);
2528 $str = str_replace("'", " ", $str);
2529 $str = str_replace('"', " ", $str);
2534 //end function js_escape
2537 function br2nl($str) {
2538 $regex = "#<[^>]+br.+?>#i";
2539 preg_match_all($regex, $str, $matches);
2541 foreach($matches[0] as $match) {
2542 $str = str_replace($match, "<br>", $str);
2545 $brs = array('<br>','<br/>', '<br />');
2546 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2547 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2548 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2549 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2555 * Private helper function for displaying the contents of a given variable.
2556 * This function is only intended to be used for SugarCRM internal development.
2557 * The ppd stands for Pre Print Die.
2559 function _ppd($mixed)
2565 * Private helper function for displaying the contents of a given variable in
2566 * the Logger. This function is only intended to be used for SugarCRM internal
2567 * development. The pp stands for Pre Print.
2568 * @param $mixed var to print_r()
2569 * @param $die boolean end script flow
2570 * @param $displayStackTrace also show stack trace
2572 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2573 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2575 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2579 $mix = print_r($mixed, true); // send print_r() output to $mix
2580 $stack = debug_backtrace();
2582 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2583 $GLOBALS['log']->$loglevel($mix);
2584 if($displayStackTrace) {
2585 foreach($stack as $position) {
2586 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2590 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2591 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2599 * private helper function to quickly show the major, direct, field attributes of a given bean.
2600 * The ppf stands for Pre[formatted] Print Focus [object]
2601 * @param object bean The focus bean
2603 function _ppf($bean, $die=false) {
2609 * Private helper function for displaying the contents of a given variable.
2610 * This function is only intended to be used for SugarCRM internal development.
2611 * The pp stands for Pre Print.
2613 function _pp($mixed)
2618 * Private helper function for displaying the contents of a given variable.
2619 * This function is only intended to be used for SugarCRM internal development.
2620 * The pp stands for Pre Print.
2622 function _pstack_trace($mixed=NULL)
2627 * Private helper function for displaying the contents of a given variable.
2628 * This function is only intended to be used for SugarCRM internal development.
2629 * The pp stands for Pre Print Trace.
2631 function _ppt($mixed, $textOnly=false)
2636 * Private helper function for displaying the contents of a given variable.
2637 * This function is only intended to be used for SugarCRM internal development.
2638 * The pp stands for Pre Print Trace Die.
2640 function _pptd($mixed)
2645 * Private helper function for decoding javascript UTF8
2646 * This function is only intended to be used for SugarCRM internal development.
2648 function decodeJavascriptUTF8($str) {
2652 * Will check if a given PHP version string is supported (tested on this ver),
2653 * unsupported (results unknown), or invalid (something will break on this
2654 * ver). Do not pass in any pararameter to default to a check against the
2655 * current environment's PHP version.
2657 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2659 function check_php_version($sys_php_version = '') {
2660 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2661 // versions below $min_considered_php_version considered invalid by default,
2662 // versions equal to or above this ver will be considered depending
2663 // on the rules that follow
2664 $min_considered_php_version = '5.2.1';
2666 // only the supported versions,
2667 // should be mutually exclusive with $invalid_php_versions
2668 $supported_php_versions = array (
2669 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2672 // invalid versions above the $min_considered_php_version,
2673 // should be mutually exclusive with $supported_php_versions
2675 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2676 $invalid_php_versions = array('5.2.7');
2678 // default unsupported
2681 // versions below $min_considered_php_version are invalid
2682 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2686 // supported version check overrides default unsupported
2687 foreach($supported_php_versions as $ver) {
2688 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2694 // invalid version check overrides default unsupported
2695 foreach($invalid_php_versions as $ver) {
2696 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2702 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2703 //and the php version contains 'rh' characters
2704 if(strpos($sys_php_version, 'rh') !== false) {
2712 * Will check if a given IIS version string is supported (tested on this ver),
2713 * unsupported (results unknown), or invalid (something will break on this
2716 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2718 function check_iis_version($sys_iis_version = '') {
2720 $server_software = $_SERVER["SERVER_SOFTWARE"];
2722 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2723 $iis_version = $out[1][0];
2725 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2727 // versions below $min_considered_iis_version considered invalid by default,
2728 // versions equal to or above this ver will be considered depending
2729 // on the rules that follow
2730 $min_considered_iis_version = '6.0';
2732 // only the supported versions,
2733 // should be mutually exclusive with $invalid_iis_versions
2734 $supported_iis_versions = array ('6.0', '7.0',);
2735 $unsupported_iis_versions = array();
2736 $invalid_iis_versions = array('5.0',);
2738 // default unsupported
2741 // versions below $min_considered_iis_version are invalid
2742 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2746 // supported version check overrides default unsupported
2747 foreach($supported_iis_versions as $ver) {
2748 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2754 // unsupported version check overrides default unsupported
2755 foreach($unsupported_iis_versions as $ver) {
2756 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2762 // invalid version check overrides default unsupported
2763 foreach($invalid_iis_versions as $ver) {
2764 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2773 function pre_login_check(){
2774 global $action, $login_error;
2775 if(!empty($action)&& $action == 'Login'){
2777 if(!empty($login_error)){
2778 $login_error = htmlentities($login_error);
2779 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2780 $_SESSION['login_error'] = $login_error;
2782 function set_focus() {}
2783 if(document.getElementById("post_error")) {
2784 document.getElementById("post_error").innerHTML="'. $login_error. '";
2785 document.getElementById("cant_login").value=1;
2786 document.getElementById("login_button").disabled = true;
2787 document.getElementById("user_name").disabled = true;
2788 //document.getElementById("user_password").disabled = true;
2797 function sugar_cleanup($exit = false) {
2798 static $called = false;
2801 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2802 chdir(realpath(dirname(__FILE__) . '/..'));
2803 global $sugar_config;
2804 require_once('include/utils/LogicHook.php');
2805 LogicHook::initialize();
2806 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2808 //added this check to avoid errors during install.
2809 if (empty($sugar_config['dbconfig'])) {
2810 if ($exit) exit; else return;
2813 if (!class_exists('Tracker', true)) {
2814 require_once 'modules/Trackers/Tracker.php';
2817 // Now write the cached tracker_queries
2818 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2819 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2820 $GLOBALS['current_user']->savePreferencesToDB();
2823 //check to see if this is not an `ajax call AND the user preference error flag is set
2825 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2826 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2827 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2828 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2831 global $app_strings;
2832 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2833 $err_mess = $app_strings['ERROR_USER_PREFS'];
2834 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2837 ajaxStatus.flashStatus('$err_mess',7000);
2843 if(class_exists('DBManagerFactory')) {
2844 $db = DBManagerFactory::getInstance();
2852 register_shutdown_function('sugar_cleanup');
2856 check_logic_hook - checks to see if your custom logic is in the logic file
2857 if not, it will add it. If the file isn't built yet, it will create the file
2860 function check_logic_hook_file($module_name, $event, $action_array){
2861 require_once('include/utils/logic_utils.php');
2864 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2866 $hook_array = get_hook_array($module_name);
2868 if(check_existing_element($hook_array, $event, $action_array)==true){
2869 //the hook at hand is present, so do nothing
2874 if(!empty($hook_array[$event]))
2876 $logic_count = count($hook_array[$event]);
2879 if($action_array[0]==""){
2880 $action_array[0] = $logic_count + 1;
2882 $hook_array[$event][] = $action_array;
2885 //end if the file exists already
2888 if($action_array[0]==""){
2889 $action_array[0] = 1;
2891 $hook_array = array();
2892 $hook_array[$event][] = $action_array;
2893 //end if else file exists already
2895 if($add_logic == true){
2897 //reorder array by element[0]
2898 //$hook_array = reorder_array($hook_array, $event);
2899 //!!!Finish this above TODO
2901 $new_contents = replace_or_add_logic_type($hook_array);
2902 write_logic_file($module_name, $new_contents);
2904 //end if add_element is true
2907 //end function check_logic_hook_file
2910 function remove_logic_hook($module_name, $event, $action_array) {
2911 require_once('include/utils/logic_utils.php');
2914 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2915 // The file exists, let's make sure the hook is there
2916 $hook_array = get_hook_array($module_name);
2918 if(check_existing_element($hook_array, $event, $action_array)==true){
2919 // The hook is there, time to take it out.
2921 foreach ( $hook_array[$event] as $i => $hook ) {
2922 // We don't do a full comparison below just in case the filename changes
2923 if ( $hook[0] == $action_array[0]
2924 && $hook[1] == $action_array[1]
2925 && $hook[3] == $action_array[3]
2926 && $hook[4] == $action_array[4] ) {
2927 unset($hook_array[$event][$i]);
2931 $new_contents = replace_or_add_logic_type($hook_array);
2932 write_logic_file($module_name, $new_contents);
2938 function display_stack_trace($textOnly=false){
2940 $stack = debug_backtrace();
2942 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2950 foreach($stack as $item) {
2956 if(isset($item['file']))
2957 $file = $item['file'];
2958 if(isset($item['class']))
2959 $class = $item['class'];
2960 if(isset($item['line']))
2961 $line = $item['line'];
2962 if(isset($item['function']))
2963 $function = $item['function'];
2967 $out .= '<font color="black"><b>';
2973 $out .= '</b></font><font color="blue">';
2976 $out .= "[L:{$line}]";
2979 $out .= '</font><font color="red">';
2982 $out .= "({$class}:{$function})";
2985 $out .= '</font><br>';
2997 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2998 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2999 $halt_script = true;
3001 case 2048: return; //depricated we have lots of these ignore them
3004 if ( error_reporting() & E_NOTICE ) {
3005 $halt_script = false;
3011 case E_USER_WARNING:
3012 case E_COMPILE_WARNING:
3013 case E_CORE_WARNING:
3016 $halt_script = false;
3021 case E_COMPILE_ERROR:
3025 $type = "Fatal Error";
3030 $type = "Parse Error";
3034 //don't know what it is might not be so bad
3035 $halt_script = false;
3036 $type = "Unknown Error ($errno)";
3039 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3041 display_stack_trace();
3051 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3053 set_error_handler('StackTraceErrorHandler');
3055 function get_sub_cookies($name){
3057 if(isset($_COOKIE[$name])){
3058 $subs = explode('#', $_COOKIE[$name]);
3059 foreach($subs as $cookie){
3060 if(!empty($cookie)){
3061 $cookie = explode('=', $cookie);
3063 $cookies[$cookie[0]] = $cookie[1];
3072 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3074 if(!empty($sub_object_array)){
3076 foreach($sub_object_array as $sub_object){
3078 //run_second level is set to true if you need to remove sub-sub components
3079 if($run_second_level==true){
3081 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3083 //end if run_second_level is true
3085 $sub_object->mark_deleted($sub_object->id);
3086 //end foreach sub component
3088 //end if this is not empty
3091 //end function mark_delete_components
3095 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3097 function return_bytes($val)
3100 $last = strtolower($val{strlen($val)-1});
3104 // The 'G' modifier is available since PHP 5.1.0
3117 * Adds the href HTML tags around any URL in the $string
3119 function url2html($string) {
3121 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3122 return $return_string;
3124 // End customization by Julian
3127 * tries to determine whether the Host machine is a Windows machine
3129 function is_windows() {
3130 static $is_windows = null;
3131 if (!isset($is_windows)) {
3132 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3138 * equivalent for windows filesystem for PHP's is_writable()
3139 * @param string file Full path to the file/dir
3140 * @return bool true if writable
3142 function is_writable_windows($file) {
3143 if($file{strlen($file)-1}=='/') {
3144 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3147 // the assumption here is that Windows has an inherited permissions scheme
3148 // any file that is a descendant of an unwritable directory will inherit
3149 // that property and will trigger a failure below.
3154 $file = str_replace("/", '\\', $file);
3156 if(file_exists($file)) {
3157 if (!($f = @sugar_fopen($file, 'r+')))
3163 if(!($f = @sugar_fopen($file, 'w')))
3172 * best guesses Timezone based on webserver's TZ settings
3174 function lookupTimezone($userOffset = 0)
3176 return TimeDate::guessTimezone($userOffset);
3179 function convert_module_to_singular($module_array){
3182 foreach($module_array as $key => $value){
3183 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3185 if($value=="Cases") {
3186 $module_array[$key] = "Case";
3188 if($key=="projecttask"){
3189 $module_array['ProjectTask'] = "Project Task";
3190 unset($module_array[$key]);
3194 return $module_array;
3196 //end function convert_module_to_singular
3200 * Given the bean_name which may be plural or singular return the singular
3201 * bean_name. This is important when you need to include files.
3203 function get_singular_bean_name($bean_name){
3204 global $beanFiles, $beanList;
3205 if(array_key_exists($bean_name, $beanList)){
3206 return $beanList[$bean_name];
3214 * Given the potential module name (singular name, renamed module name)
3215 * Return the real internal module name.
3217 function get_module_from_singular($singular) {
3219 // find the internal module name for a singular name
3220 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3222 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3224 foreach ($singular_modules as $mod_name=>$sin_name) {
3225 if ($singular == $sin_name and $mod_name != $sin_name) {
3231 // find the internal module name for a renamed module
3232 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3234 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3236 foreach ($moduleList as $mod_name=>$name) {
3237 if ($singular == $name and $mod_name != $name) {
3243 // if it's not a singular name, nor a renamed name, return the original value
3247 function get_label($label_tag, $temp_module_strings){
3248 global $app_strings;
3249 if(!empty($temp_module_strings[$label_tag])){
3251 $label_name = $temp_module_strings[$label_tag];
3253 if(!empty($app_strings[$label_tag])){
3254 $label_name = $app_strings[$label_tag];
3256 $label_name = $label_tag;
3261 //end function get_label
3265 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3267 $rel_list = array();
3269 foreach($focus->relationship_fields as $rel_key => $rel_value){
3270 if($rel_value == $relationship_name){
3271 $temp_bean = get_module_info($tar_rel_module);
3272 // echo $focus->$rel_key;
3273 $temp_bean->retrieve($focus->$rel_key);
3274 if($temp_bean->id!=""){
3276 $rel_list[] = $temp_bean;
3282 foreach($focus->field_defs as $field_name => $field_def){
3283 //Check if the relationship_name matches a "relate" field
3284 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3285 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3286 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3287 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3289 $temp_bean = get_module_info($tar_rel_module);
3290 // echo $focus->$field_def['id_name'];
3291 $temp_bean->retrieve($focus->$field_def['id_name']);
3292 if($temp_bean->id!=""){
3294 $rel_list[] = $temp_bean;
3297 //Check if the relationship_name matches a "link" in a relate field
3298 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3299 $temp_bean = get_module_info($tar_rel_module);
3300 // echo $focus->$rel_value['id_name'];
3301 $temp_bean->retrieve($focus->$rel_value['id_name']);
3302 if($temp_bean->id!=""){
3304 $rel_list[] = $temp_bean;
3310 // special case for unlisted parent-type relationships
3311 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3312 $temp_bean = get_module_info($tar_rel_module);
3313 $temp_bean->retrieve($focus->parent_id);
3314 if($temp_bean->id!=""){
3315 $rel_list[] = $temp_bean;
3322 //end function search_filter_rel_info
3325 function get_module_info($module_name){
3329 //Get dictionary and focus data for module
3330 $vardef_name = $beanList[$module_name];
3332 if($vardef_name=="aCase"){
3333 $class_name = "Case";
3335 $class_name = $vardef_name;
3338 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3342 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3344 $module_bean = new $vardef_name();
3345 return $module_bean;
3346 //end function get_module_table
3350 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3352 * @param string $moduleName
3354 function get_valid_bean_name($module_name){
3357 $vardef_name = $beanList[$module_name];
3358 if($vardef_name=="aCase"){
3359 $bean_name = "Case";
3361 $bean_name = $vardef_name;
3368 function checkAuthUserStatus(){
3375 * This function returns an array of phpinfo() results that can be parsed and
3376 * used to figure out what version we run, what modules are compiled in, etc.
3377 * @param $level int info level constant (1,2,4,8...64);
3378 * @return $returnInfo array array of info about the PHP environment
3379 * @author original by "code at adspeed dot com" Fron php.net
3380 * @author customized for Sugar by Chris N.
3382 function getPhpInfo($level=-1) {
3383 /** Name (constant) Value Description
3384 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3385 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3386 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3387 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3388 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3389 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3390 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3391 INFO_ALL -1 Shows all of the above. This is the default value.
3395 $phpinfo = ob_get_contents();
3398 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3399 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3400 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3401 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3404 $returnInfo = array();
3406 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3407 $returnInfo['PHP Version'] = $version[1];
3411 for ($i=1; $i<count($parsedInfo); $i++) {
3412 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3413 $vName = trim($match[1]);
3414 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3416 foreach ($parsedInfo2 AS $vOne) {
3417 $vPat = '<info>([^<]+)<\/info>';
3418 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3419 $vPat2 = "/$vPat\s*$vPat/";
3421 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3422 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3423 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3424 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3436 * This function will take a string that has tokens like {0}, {1} and will replace
3437 * those tokens with the args provided
3438 * @param $format string to format
3439 * @param $args args to replace
3440 * @return $result a formatted string
3442 function string_format($format, $args){
3446 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3447 * IN () fails and IN ('') works.
3449 if (count($args) == 1)
3452 $singleArgument = current($args);
3453 if (empty($singleArgument))
3455 return str_replace("{0}", "''", $result);
3460 for($i = 0; $i < count($args); $i++){
3461 $result = str_replace('{'.$i.'}', $args[$i], $result);
3467 * Generate a string for displaying a unique identifier that is composed
3468 * of a system_id and number. This is use to allow us to generate quote
3469 * numbers using a DB auto-increment key from offline clients and still
3470 * have the number be unique (since it is modified by the system_id.
3472 * @param $num of bean
3473 * @param $system_id from system
3474 * @return $result a formatted string
3476 function format_number_display($num, $system_id){
3477 global $sugar_config;
3478 if(isset($num) && !empty($num)){
3479 $num=unformat_number($num);
3480 if(isset($system_id) && $system_id == 1){
3481 return sprintf("%d", $num);
3484 return sprintf("%d-%d", $num, $system_id);
3488 function checkLoginUserStatus(){
3492 * This function will take a number and system_id and format
3493 * @param $url URL containing host to append port
3494 * @param $port the port number - if '' is passed, no change to url
3495 * @return $resulturl the new URL with the port appended to the host
3497 function appendPortToHost($url, $port)
3501 // if no port, don't change the url
3504 $split = explode("/", $url);
3505 //check if it starts with http, in case they didn't include that in url
3506 if(str_begin($url, 'http'))
3508 //third index ($split[2]) will be the host
3509 $split[2] .= ":".$port;
3511 else // otherwise assumed to start with host name
3513 //first index ($split[0]) will be the host
3514 $split[0] .= ":".$port;
3517 $resulturl = implode("/", $split);
3524 * Singleton to return JSON object
3525 * @return JSON object
3527 function getJSONobj() {
3528 static $json = null;
3530 require_once('include/JSON.php');
3531 $json = new JSON(JSON_LOOSE_TYPE);
3536 require_once('include/utils/db_utils.php');
3539 * Set default php.ini settings for entry points
3541 function setPhpIniSettings() {
3543 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3545 if(function_exists('gzclose') && headers_sent() == false) {
3546 ini_set('zlib.output_compression', 1);
3550 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3552 /*if(function_exists('mb_strlen')) {
3553 ini_set('mbstring.func_overload', 7);
3554 ini_set('mbstring.internal_encoding', 'UTF-8');
3558 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3559 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3560 $backtrack_limit = ini_get('pcre.backtrack_limit');
3561 if(!empty($backtrack_limit)) {
3562 ini_set('pcre.backtrack_limit', '-1');
3567 * like array_merge() but will handle array elements that are themselves arrays;
3568 * PHP's version just overwrites the element with the new one.
3570 * @internal Note that this function deviates from the internal array_merge()
3571 * functions in that it does does not treat numeric keys differently
3572 * than string keys. Additionally, it deviates from
3573 * array_merge_recursive() by not creating an array when like values
3576 * @param array gimp the array whose values will be overloaded
3577 * @param array dom the array whose values will pwn the gimp's
3578 * @return array beaten gimp
3580 function sugarArrayMerge($gimp, $dom) {
3581 if(is_array($gimp) && is_array($dom)) {
3582 foreach($dom as $domKey => $domVal) {
3583 if(array_key_exists($domKey, $gimp)) {
3584 if(is_array($domVal)) {
3586 foreach ( $domVal as $domArrKey => $domArrVal )
3587 $tempArr[$domArrKey] = $domArrVal;
3588 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3589 if ( !array_key_exists($gimpArrKey, $tempArr) )
3590 $tempArr[$gimpArrKey] = $gimpArrVal;
3591 $gimp[$domKey] = $tempArr;
3593 $gimp[$domKey] = $domVal;
3596 $gimp[$domKey] = $domVal;
3600 // if the passed value for gimp isn't an array, then return the $dom
3601 elseif(is_array($dom))
3608 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3610 * @param array gimp the array whose values will be overloaded
3611 * @param array dom the array whose values will pwn the gimp's
3612 * @return array beaten gimp
3614 function sugarArrayMergeRecursive($gimp, $dom) {
3615 if(is_array($gimp) && is_array($dom)) {
3616 foreach($dom as $domKey => $domVal) {
3617 if(array_key_exists($domKey, $gimp)) {
3618 if(is_array($domVal) && is_array($gimp[$domKey])) {
3619 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3621 $gimp[$domKey] = $domVal;
3624 $gimp[$domKey] = $domVal;
3628 // if the passed value for gimp isn't an array, then return the $dom
3629 elseif(is_array($dom))
3636 * finds the correctly working versions of PHP-JSON
3637 * @return bool True if NOT found or WRONG version
3639 function returnPhpJsonStatus() {
3640 if(function_exists('json_encode')) {
3641 $phpInfo = getPhpInfo(8);
3642 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3644 return true; // not found
3649 * getTrackerSubstring
3651 * Returns a [number]-char or less string for the Tracker to display in the header
3652 * based on the tracker_max_display_length setting in config.php. If not set,
3653 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3655 * @param string name field for a given Object
3656 * @return string [number]-char formatted string if length of string exceeds the max allowed
3658 function getTrackerSubstring($name) {
3659 static $max_tracker_item_length;
3662 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3663 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3665 global $sugar_config;
3667 if(!isset($max_tracker_item_length)) {
3668 if(isset($sugar_config['tracker_max_display_length'])) {
3669 $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;
3671 $max_tracker_item_length = 15;
3675 if($strlen > $max_tracker_item_length) {
3676 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length);
3683 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3684 $where_clauses= array();
3686 $table_name=$bean->object_name;
3687 foreach ($field_list[$module] as $field=>$parms) {
3688 if(isset($values[$field]) && $values[$field] != "") {
3690 if (!empty($parms['operator'])) {
3691 $operator=$parms['operator'];
3693 if (is_array($values[$field])) {
3696 foreach ($values[$field] as $key => $val) {
3697 if ($val != ' ' and $val != '') {
3698 if (!empty($field_value)) {
3701 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3705 $field_value=$GLOBALS['db']->quote($values[$field]);
3707 //set db_fields array.
3708 if (!isset($parms['db_field']) ) {
3709 $parms['db_field'] = array($field);
3711 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3712 global $current_user;
3713 $field_value = $GLOBALS['db']->quote($current_user->id);
3719 if ($field_value != '') {
3721 foreach ($parms['db_field'] as $db_field) {
3722 if (strstr($db_field,'.')===false) {
3723 $db_field=$bean->table_name.".".$db_field;
3725 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3726 $db_field='upper('.$db_field.")";
3727 $field_value=strtoupper($field_value);
3731 if (!empty($where)) {
3734 switch (strtolower($operator)) {
3736 $where .= $db_field . " like '".$field_value.$like_char."'";
3739 $where .= $db_field . " in (".$field_value.')';
3742 $where .= $db_field . " = '".$field_value ."'";
3747 if (!empty($where)) {
3749 array_push($where_clauses, '( '.$where.' )');
3751 array_push($where_clauses, $where);
3756 if ($add_custom_fields) {
3757 require_once('modules/DynamicFields/DynamicField.php');
3758 $bean->setupCustomFields($module);
3759 $bean->custom_fields->setWhereClauses($where_clauses);
3761 return $where_clauses;
3764 function add_quotes($str) {
3769 * This function will rebuild the config file
3770 * @param $sugar_config
3771 * @param $sugar_version
3772 * @return bool true if successful
3774 function rebuildConfigFile($sugar_config, $sugar_version) {
3775 // add defaults to missing values of in-memory sugar_config
3776 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3777 // need to override version with default no matter what
3778 $sugar_config['sugar_version'] = $sugar_version;
3780 ksort( $sugar_config );
3782 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3791 * getJavascriptSiteURL
3792 * This function returns a URL for the client javascript calls to access
3793 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3794 * are used to access the site. Thus, the hostname in the URL returned may
3795 * not always match that of $sugar_config['site_url']. Basically, the
3796 * assumption is that however the user accessed the website is how they
3797 * will continue to with subsequent javascript requests. If the variable
3798 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3799 * @return $site_url The url used to refer to the website
3801 function getJavascriptSiteURL() {
3802 global $sugar_config;
3803 if(!empty($_SERVER['HTTP_REFERER'])) {
3804 $url = parse_url($_SERVER['HTTP_REFERER']);
3805 $replacement_url = $url['scheme']."://".$url['host'];
3806 if(!empty($url['port']))
3807 $replacement_url .= ':'.$url['port'];
3808 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3810 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3811 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3812 $site_url = preg_replace('/^http\:/','https:',$site_url);
3815 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3819 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3820 function add_squotes($str) {
3821 return "'" . $str . "'";
3825 // recursive function to count the number of levels within an array
3826 function array_depth($array, $depth_count=-1, $depth_array=array()){
3828 if (is_array($array)){
3829 foreach ($array as $key => $value){
3830 $depth_array[] = array_depth($value, $depth_count);
3834 return $depth_count;
3836 foreach ($depth_array as $value){
3837 $depth_count = $value > $depth_count ? $value : $depth_count;
3839 return $depth_count;
3843 * Creates a new Group User
3844 * @param string $name Name of Group User
3845 * @return string GUID of new Group User
3847 function createGroupUser($name) {
3850 $group = new User();
3851 $group->user_name = $name;
3852 $group->last_name = $name;
3853 $group->is_group = 1;
3854 $group->deleted = 0;
3855 $group->status = 'Active'; // cn: bug 6711
3856 $group->setPreference('timezone', TimeDate::userTimezone());
3863 * Helper function to locate an icon file given only a name
3864 * Searches through the various paths for the file
3865 * @param string iconFileName The filename of the icon
3866 * @return string Relative pathname of the located icon, or '' if not found
3869 function _getIcon($iconFileName)
3872 $iconName = "icon_{$iconFileName}.gif";
3873 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3875 //First try un-ucfirst-ing the icon name
3876 if ( empty($iconFound) )
3877 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3878 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3880 //Next try removing the icon prefix
3881 if ( empty($iconFound) )
3882 $iconName = "{$iconFileName}.gif";
3883 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3885 if ( empty($iconFound) )
3891 * Function to grab the correct icon image for Studio
3892 * @param string $iconFileName Name of the icon file
3893 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3894 * @param string $width Width of image
3895 * @param string $height Height of image
3896 * @param string $align Alignment of image
3897 * @param string $alt Alt tag of image
3898 * @return string $string <img> tag with corresponding image
3901 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
3903 global $app_strings, $theme;
3905 $iconName = _getIcon($iconFileName);
3906 if(empty($iconName)){
3907 $iconName = _getIcon($altFileName);
3908 if (empty($iconName))
3910 return $app_strings['LBL_NO_IMAGE'];
3913 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3917 * Function to grab the correct icon image for Dashlets Dialog
3918 * @param string $filename Location of the icon file
3919 * @param string $module Name of the module to fall back onto if file does not exist
3920 * @param string $width Width of image
3921 * @param string $height Height of image
3922 * @param string $align Alignment of image
3923 * @param string $alt Alt tag of image
3924 * @return string $string <img> tag with corresponding image
3927 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
3928 global $app_strings, $theme;
3929 $iconName = _getIcon($module . "_32");
3930 if (empty($iconName))
3932 $iconName = _getIcon($module);
3934 if(empty($iconName)){
3935 return $app_strings['LBL_NO_IMAGE'];
3937 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3940 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3941 function html_entity_decode_utf8($string)
3944 // replace numeric entities
3945 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3946 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3947 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
3948 // replace literal entities
3949 if (!isset($trans_tbl))
3951 $trans_tbl = array();
3952 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3953 $trans_tbl[$key] = utf8_encode($val);
3955 return strtr($string, $trans_tbl);
3958 // Returns the utf string corresponding to the unicode value
3959 function code2utf($num)
3961 if ($num < 128) return chr($num);
3962 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3963 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3964 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3968 function str_split_php4($string, $length = 1) {
3969 $string_length = strlen($string);
3972 if ($length > $string_length) {
3973 // use the string_length as the string is shorter than the length
3974 $length = $string_length;
3976 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3977 $return[] = substr($string, $cursor, $length);
3982 if (version_compare(phpversion(), '5.0.0', '<')) {
3983 function str_split($string, $length = 1) {
3984 return str_split_php4($string, $length);
3989 * @deprecated use DBManagerFactory::isFreeTDS
3991 function is_freetds()
3993 return DBManagerFactory::isFreeTDS();
3997 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3999 * @todo this won't work completely right until we impliment css compression and combination
4000 * for now, we'll just include the last css file found.
4002 * @return chart.css file to use
4004 function chartStyle()
4006 return SugarThemeRegistry::current()->getCSSURL('chart.css');
4010 * Chart dashlet helper functions that returns the correct XML color file for charts,
4011 * dependent on the current theme.
4013 * @return sugarColors.xml to use
4015 function chartColors()
4017 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
4018 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4019 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4021 /* End Chart Dashlet helper functions */
4024 * This function is designed to set up the php enviroment
4025 * for AJAX requests.
4028 function ajaxInit() {
4029 ini_set('display_errors', 'false');
4033 * Returns an absolute path from the given path, determining if it is relative or absolute
4035 * @param string $path
4038 function getAbsolutePath(
4040 $currentServer = false
4043 $path = trim($path);
4045 // try to match absolute paths like \\server\share, /directory or c:\
4046 if ( ( substr($path,0,2) == '\\\\' )
4047 || ( $path[0] == '/' )
4048 || preg_match('/^[A-z]:/i',$path)
4052 return getcwd().'/'.$path;
4056 * Returns the bean object of the given module
4058 * @deprecated use SugarModule::loadBean() instead
4059 * @param string $module
4066 return SugarModule::get($module)->loadBean();
4071 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4073 function isTouchScreen()
4075 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4077 // first check if we have forced use of the touch enhanced interface
4078 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4082 // next check if we should use the touch interface with our device
4083 if ( strpos($ua, 'ipad') !== false ) {
4091 * Returns the shortcut keys to access the shortcut links. Shortcut
4092 * keys vary depending on browser versions and operating systems.
4093 * @return String value of the shortcut keys
4095 function get_alt_hot_key() {
4097 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4098 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4099 $isMac = strpos($ua, 'mac') !== false;
4100 $isLinux = strpos($ua, 'linux') !== false;
4102 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4103 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4104 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4107 return $isMac ? 'Ctrl+' : 'Alt+';
4110 function can_start_session(){
4111 if(!empty($_GET['PHPSESSID'])) {
4114 $session_id = session_id();
4115 return empty($session_id) ? true : false;
4118 function load_link_class($properties){
4120 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4121 require_once($properties['link_file']);
4122 $class = $properties['link_class'];
4128 function inDeveloperMode()
4130 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4134 * Filter the protocol list for inbound email accounts.
4136 * @param array $protocol
4138 function filterInboundEmailPopSelection($protocol)
4140 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4142 if( isset($protocol['pop3']) )
4143 unset($protocol['pop3']);
4146 $protocol['pop3'] = 'POP3';
4152 * The function is used because currently we are not supporting mbstring.func_overload
4153 * 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.
4154 * 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.
4155 * @returns the substred strings.
4157 function sugar_substr($string, $length, $charset='UTF-8')
4159 if(mb_strlen($string,$charset) > $length) {
4160 $string = trim(mb_substr(trim($string),0,$length,$charset));
4166 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4167 * This will work even without setting the mbstring.*encoding
4169 function sugar_ucfirst($string, $charset='UTF-8') {
4170 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4177 function unencodeMultienum($string) {
4178 if (is_array($string))
4182 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4183 $string = substr(substr($string, 1), 0, strlen($string) -2);
4186 return explode('^,^', $string);
4189 function encodeMultienumValue($arr) {
4190 if (!is_array($arr))
4196 $string = "^" . implode('^,^', $arr) . "^";
4202 * create_export_query is used for export and massupdate
4203 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4204 * This function will correct the where clause and output necessary join condition for them
4205 * @param $module: the module name
4206 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4207 * @param $where: where clauses
4208 * @return $ret_array['where']: corrected where clause
4209 * @return $ret_array['join']: extra join condition
4211 function create_export_query_relate_link_patch($module, $searchFields, $where){
4212 if(file_exists('modules/'.$module.'/SearchForm.html')){
4213 $ret_array['where'] = $where;
4216 $seed = loadBean($module);
4217 foreach($seed->field_defs as $name=>$field)
4220 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4221 $seed->load_relationship($field['link']);
4223 if(empty($join_type))
4225 $params['join_type'] = ' LEFT JOIN ';
4229 $params['join_type'] = $join_type;
4231 if(isset($data['join_name']))
4233 $params['join_table_alias'] = $field['join_name'];
4237 $params['join_table_alias'] = 'join_'.$field['name'];
4240 if(isset($data['join_link_name']))
4242 $params['join_table_link_alias'] = $field['join_link_name'];
4246 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4248 $join = $seed->$field['link']->getJoin($params, true);
4249 $join_table_alias = 'join_'.$field['name'];
4250 if(isset($field['db_concat_fields'])){
4251 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4252 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4254 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4258 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4263 * 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.
4264 * @Depends on QuickRepairAndRebuild.php
4265 * @Relate bug 30642 ,23177
4267 function clearAllJsAndJsLangFilesWithoutOutput(){
4268 global $current_language , $mod_strings;
4269 $MBmodStrings = $mod_strings;
4270 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4271 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4272 $repair = new RepairAndClear();
4273 $repair->module_list = array();
4274 $repair->show_output = false;
4275 $repair->clearJsLangFiles();
4276 $repair->clearJsFiles();
4277 $mod_strings = $MBmodStrings;
4281 * This function will allow you to get a variable value from query string
4283 function getVariableFromQueryString($variable, $string){
4285 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4295 * should_hide_iframes
4296 * This is a helper method to determine whether or not to show iframes (My Sites) related
4297 * information in the application.
4299 * @return boolean flag indicating whether or not iframes module should be hidden
4301 function should_hide_iframes() {
4302 //Remove the MySites module
4303 if(file_exists('modules/iFrames/iFrame.php')) {
4304 if(!class_exists("iFrame")) {
4305 require_once('modules/iFrames/iFrame.php');
4313 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4315 * @param string $version
4316 * @return string RC, BETA, GA
4318 function getVersionStatus($version){
4319 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4320 return strtoupper($matches[1]);
4327 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4328 * 5.5.1RC1 then return 5.5.1
4330 * @param string $version
4333 function getMajorMinorVersion($version){
4334 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4335 $version = $matches2[1];
4336 $arr = explode('.', $version);
4337 if(count($arr) > 2){
4339 $version = substr($version, 0, 3);
4347 * Return string composed of seconds & microseconds of current time, without dots
4350 function sugar_microtime()
4352 $now = explode(' ', microtime());
4353 $unique_id = $now[1].str_replace('.', '', $now[0]);
4358 * Extract urls from a piece of text
4360 * @return array of urls found in $string
4362 function getUrls($string)
4364 $lines = explode("<br>", trim($string));
4366 foreach($lines as $line){
4367 $regex = '/http?\:\/\/[^\" ]+/i';
4368 preg_match_all($regex, $line, $matches);
4369 foreach($matches[0] as $match){
4378 * Sanitize image file from hostile content
4379 * @param string $path Image file
4380 * @param bool $jpeg Accept only JPEGs?
4382 function verify_image_file($path, $jpeg = false)
4384 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4385 $img = imagecreatefromstring(file_get_contents($path));
4389 $img_size = getimagesize($path);
4390 $filetype = $img_size['mime'];
4391 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4392 if($filetype == "image/jpeg" || $jpeg) {
4395 $image = ob_get_clean();
4396 // not writing directly because imagejpeg does not work with streams
4397 if(file_put_contents($path, $image)) {
4400 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4401 imagealphablending($img, true);
4402 imagesavealpha($img, true);
4405 $image = ob_get_clean();
4406 if(file_put_contents($path, $image)) {
4413 // check image manually
4414 $fp = fopen($path, "rb");
4415 if(!$fp) return false;
4417 // read the whole file in chunks
4419 $data .= fread($fp,8192);
4423 if(preg_match("/<(\?php|html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
4425 $GLOBALS['log']->fatal("Found {$m[0]} in $path, not allowing upload");
4434 * Verify uploaded image
4435 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4436 * @param string $path Image path
4437 * @param bool $jpeg_only Accept only JPEGs?
4439 function verify_uploaded_image($path, $jpeg_only = false)
4441 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4443 $supportedExtensions['png'] = 'image/png';
4446 if(!file_exists($path) || !is_file($path)) {
4450 $img_size = getimagesize($path);
4451 $filetype = $img_size['mime'];
4452 $ext = end(explode(".", $path));
4453 if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4454 !in_array($filetype, array_values($supportedExtensions))) {
4457 return verify_image_file($path, $jpeg_only);
4460 function cmp_beans($a, $b)
4462 global $sugar_web_service_order_by;
4463 //If the order_by field is not valid, return 0;
4464 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4467 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4468 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4472 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4480 function order_beans($beans, $field_name)
4482 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4483 global $sugar_web_service_order_by;
4484 $sugar_web_service_order_by = $field_name;
4485 usort($beans, "cmp_beans");
4490 * Return search like string
4491 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4492 * @param string $str string to be searched
4493 * @param string $like_char Database like character, usually '%'
4494 * @return string Returns a string to be searched in db query
4496 function sql_like_string($str, $like_char) {
4498 // default behaviour
4501 // override default wildcard character
4502 if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4503 strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4504 $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4507 // add wildcard at the beginning of the search string
4508 if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4509 $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4510 if (substr($str,0,1) <> $wildcard)
4511 $str = $wildcard.$str;
4514 // add wildcard at the end of search string (default)
4515 if(substr($str,-1) <> $wildcard) {
4519 return str_replace($wildcard, $like_char, $str);
4522 //check to see if custom utils exists
4523 if(file_exists('custom/include/custom_utils.php')){
4524 include_once('custom/include/custom_utils.php');
4527 //check to see if custom utils exists in Extension framework
4528 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4529 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4532 * @param $input - the input string to sanitize
4533 * @param int $quotes - use quotes
4534 * @param string $charset - the default charset
4535 * @param bool $remove - strip tags or not
4536 * @return string - the sanitized string
4538 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4540 return htmlentities($input, $quotes, $charset);
4545 * utf8_recursive_encode
4547 * This function walks through an Array and recursively calls utf8_encode on the
4548 * values of each of the elements.
4550 * @param $data Array of data to encode
4551 * @return utf8 encoded Array data
4553 function utf8_recursive_encode($data)
4556 foreach($data as $key=>$val) {
4557 if(is_array($val)) {
4558 $result[$key] = utf8_recursive_encode($val);
4560 $result[$key] = utf8_encode($val);
4567 * get_language_header
4569 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4570 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4572 * @return String The lang=[Current Language] markup to insert into the <html> tag
4574 function get_language_header()
4576 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4581 * get_custom_file_if_exists
4583 * This function handles the repetitive code we have where we first check if a file exists in the
4584 * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
4585 * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
4586 * otherwise it return $file
4588 * @param $file String of filename to check
4589 * @return $file String of filename including custom directory if found
4591 function get_custom_file_if_exists($file)
4593 return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4600 * This will return the URL used to redirect the user to the help documentation.
4601 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4602 * in config.php or config_override.php.
4604 * @param string $send_edition
4605 * @param string $send_version
4606 * @param string $send_lang
4607 * @param string $send_module
4608 * @param string $send_action
4609 * @param string $dev_status
4610 * @param string $send_key
4611 * @param string $send_anchor
4612 * @return string the completed help URL
4614 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4615 global $sugar_config;
4617 if (!empty($sugar_config['custom_help_url'])) {
4618 $sendUrl = $sugar_config['custom_help_url'];
4620 if (!empty($sugar_config['custom_help_base_url'])) {
4621 $baseUrl= $sugar_config['custom_help_base_url'];
4623 $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4625 $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4626 if(!empty($send_anchor)) {
4627 $sendUrl .= "&anchor=".$send_anchor;