2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2013 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' => '%',
218 'min_retry_interval' => 60, // minimal job retry delay
219 'max_retries' => 5, // how many times to retry the job
220 'timeout' => 86400, // how long a job may spend as running before being force-failed
221 'soft_lifetime' => 7, // how many days until job record will be soft deleted after completion
222 'hard_lifetime' => 21, // how many days until job record will be purged from DB
225 'max_cron_jobs' => 10, // max jobs per cron schedule run
226 'max_cron_runtime' => 60, // max runtime for cron jobs
227 'min_cron_interval' => 30, // minimal interval between cron jobs
232 function get_sugar_config_defaults() {
235 * used for getting base values for array style config.php. used by the
236 * installer and to fill in new entries on upgrades. see also:
240 $sugar_config_defaults = array (
241 'admin_export_only' => false,
242 'export_delimiter' => ',',
243 'cache_dir' => 'cache/',
244 'calculate_response_time' => true,
245 'create_default_user' => false,
246 'chartEngine' => 'Jit',
247 'date_formats' => array (
248 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
249 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
250 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
251 'name_formats' => array (
252 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
253 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
255 'dbconfigoption' => array (
256 'persistent' => true,
260 'default_action' => 'index',
261 'default_charset' => return_session_value_or_default('default_charset',
263 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
264 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
265 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
266 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
267 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
268 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
269 'default_date_format' => 'm/d/Y',
270 'default_locale_name_format' => 's f l',
271 'default_export_charset' => 'UTF-8',
272 'default_language' => return_session_value_or_default('default_language',
274 'default_module' => 'Home',
275 'default_password' => '',
276 'default_permissions' => array (
282 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
283 'default_time_format' => 'h:ia',
284 'default_user_is_admin' => false,
285 'default_user_name' => '',
286 'disable_export' => false,
287 'disable_persistent_connections' =>
288 return_session_value_or_default('disable_persistent_connections',
290 'display_email_template_variable_chooser' => false,
291 'display_inbound_email_buttons' => false,
292 'dump_slow_queries' => false,
293 'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
294 'email_default_editor' => 'html',
295 'email_default_client' => 'sugar',
296 'email_default_delete_attachments' => true,
297 'history_max_viewed' => 50,
298 'installer_locked' => true,
299 'import_max_records_per_file' => 100,
300 'import_max_records_total_limit' => '',
301 'languages' => array('en_us' => 'English (US)'),
302 'large_scale_test' => false,
303 'list_max_entries_per_page' => 20,
304 'list_max_entries_per_subpanel' => 10,
305 'lock_default_user_name' => false,
306 'log_memory_usage' => false,
307 'portal_view' => 'single_user',
308 'resource_management' => array (
309 'special_query_limit' => 50000,
310 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
311 'default_limit' => 1000,
313 'require_accounts' => true,
314 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
316 'save_query' => 'all',
317 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
318 'showThemePicker' => true,
319 'slow_query_time_msec' => '100',
321 'time_formats' => array (
322 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
323 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
324 'tracker_max_display_length' => 15,
325 'translation_string_prefix' =>
326 return_session_value_or_default('translation_string_prefix', false),
327 'upload_badext' => array (
328 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
329 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
330 'upload_maxsize' => 30000000,
331 'import_max_execution_time' => 3600,
332 // 'use_php_code_json' => returnPhpJsonStatus(),
333 'verify_client_ip' => true,
334 'js_custom_version' => '',
335 'js_lang_version' => 1,
336 'lead_conv_activity_opt' => 'donothing',
337 'default_number_grouping_seperator' => ',',
338 'default_decimal_seperator' => '.',
339 'lock_homepage' => false,
340 'lock_subpanels' => false,
341 'max_dashlets_homepage' => '15',
342 'default_max_tabs' => '7',
343 'dashlet_display_row_options' => array('1','3','5','10'),
344 'default_subpanel_tabs' => true,
345 'default_subpanel_links' => false,
346 'default_swap_last_viewed' => false,
347 'default_swap_shortcuts' => false,
348 'default_navigation_paradigm' => 'gm',
349 'admin_access_control' => false,
350 'use_common_ml_dir' => false,
351 'common_ml_dir' => '',
354 'default_view' => 'week',
355 'show_calls_by_default' => true,
356 'show_tasks_by_default' => true,
357 'show_completed_by_default' => true,
358 'editview_width' => 990,
359 'editview_height' => 485,
360 'day_timestep' => 15,
361 'week_timestep' => 30,
362 'items_draggable' => true,
363 'items_resizable' => true,
364 'enable_repeat' => true,
365 'max_repeat_count' => 1000,
367 'passwordsetting' => empty($passwordsetting) ? array (
368 'SystemGeneratedPasswordON' => '',
369 'generatepasswordtmpl' => '',
370 'lostpasswordtmpl' => '',
371 'forgotpasswordON' => false,
372 'linkexpiration' => '1',
373 'linkexpirationtime' => '30',
374 'linkexpirationtype' => '1',
375 'systexpiration' => '0',
376 'systexpirationtime' => '',
377 'systexpirationtype' => '0',
378 'systexpirationlogin' => '',
379 ) : $passwordsetting,
380 'use_real_names' => true,
382 'search_wildcard_infront' => false,
383 'search_wildcard_char' => '%',
385 'min_retry_interval' => 30, // 30 seconds minimal job retry
386 'max_retries' => 5, // how many times to retry the job
387 'timeout' => 86400, // how long a job may spend as running before being force-failed
390 'max_cron_jobs' => 10, // max jobs per cron schedule run
391 'max_cron_runtime' => 30, // max runtime for cron jobs
392 'min_cron_interval' => 30, // minimal interval between cron jobs
396 if(!is_object($locale)) {
397 $locale = new Localization();
400 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
402 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
403 return( $sugar_config_defaults );
407 * @deprecated use SugarView::getMenu() instead
409 function load_menu($path){
412 if(file_exists($path . 'Menu.php'))
414 require($path . 'Menu.php');
416 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
418 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
420 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
422 require('custom/application/Ext/Menus/menu.ext.php');
428 * get_notify_template_file
429 * This function will return the location of the email notifications template to use
431 * @return string relative file path to email notifications template file
433 function get_notify_template_file($language){
435 * Order of operation:
436 * 1) custom version of specified language
437 * 2) stock version of specified language
438 * 3) custom version of en_us template
439 * 4) stock en_us template
442 // set $file to the base code template so it's set if none of the conditions pass
443 $file = "include/language/en_us.notify_template.html";
445 if(file_exists("custom/include/language/{$language}.notify_template.html")){
446 $file = "custom/include/language/{$language}.notify_template.html";
448 else if(file_exists("include/language/{$language}.notify_template.html")){
449 $file = "include/language/{$language}.notify_template.html";
451 else if(file_exists("custom/include/language/en_us.notify_template.html")){
452 $file = "custom/include/language/en_us.notify_template.html";
458 function sugar_config_union( $default, $override ){
459 // a little different then array_merge and array_merge_recursive. we want
460 // the second array to override the first array if the same value exists,
461 // otherwise merge the unique keys. it handles arrays of arrays recursively
462 // might be suitable for a generic array_union
463 if( !is_array( $override ) ){
466 foreach( $default as $key => $value ){
467 if( !array_key_exists($key, $override) ){
468 $override[$key] = $value;
470 else if( is_array( $key ) ){
471 $override[$key] = sugar_config_union( $value, $override[$key] );
477 function make_not_writable( $file ){
478 // Returns true if the given file/dir has been made not writable
480 if( is_file($file) || is_dir($file) ){
481 if( !is_writable($file) ){
485 $original_fileperms = fileperms($file);
487 // take away writable permissions
488 $new_fileperms = $original_fileperms & ~0x0092;
489 @sugar_chmod($file, $new_fileperms);
491 if( !is_writable($file) ){
500 /** This function returns the name of the person.
501 * It currently returns "first last". It should not put the space if either name is not available.
502 * It should not return errors if either name is not available.
503 * If no names are present, it will return ""
504 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
505 * All Rights Reserved.
506 * Contributor(s): ______________________________________..
508 function return_name($row, $first_column, $last_column)
514 if(isset($row[$first_column]))
516 $first_name = stripslashes($row[$first_column]);
519 if(isset($row[$last_column]))
521 $last_name = stripslashes($row[$last_column]);
524 $full_name = $first_name;
526 // If we have a first name and we have a last name
527 if($full_name != "" && $last_name != "")
529 // append a space, then the last name
530 $full_name .= " ".$last_name;
532 // If we have no first name, but we have a last name
533 else if($last_name != "")
535 // append the last name without the space.
536 $full_name .= $last_name;
543 function get_languages()
545 global $sugar_config;
546 $lang = $sugar_config['languages'];
547 if(!empty($sugar_config['disabled_languages'])){
548 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
549 unset($lang[$disable]);
555 function get_all_languages()
557 global $sugar_config;
558 return $sugar_config['languages'];
562 function get_language_display($key)
564 global $sugar_config;
565 return $sugar_config['languages'][$key];
568 function get_assigned_user_name($assigned_user_id, $is_group = '') {
569 static $saved_user_list = null;
571 if(empty($saved_user_list)) {
572 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
575 if(isset($saved_user_list[$assigned_user_id])) {
576 return $saved_user_list[$assigned_user_id];
583 * retrieves the user_name column value (login)
584 * @param string id GUID of user
587 function get_user_name($id) {
591 $db = DBManagerFactory::getInstance();
593 $q = "SELECT user_name FROM users WHERE id='{$id}'";
595 $a = $db->fetchByAssoc($r);
597 return (empty($a)) ? '' : $a['user_name'];
601 //TODO Update to use global cache
605 * This is a helper function to return an Array of users depending on the parameters passed into the function.
606 * This function uses the get_register_value function by default to use a caching layer where supported.
608 * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
609 * @param string $status String value indicating the status to filter users by, "Active" by default
610 * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
611 * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
612 * @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
613 * @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
614 * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
615 * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
617 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) {
619 global $sugar_config;
622 $locale = new Localization();
626 $key_name = $add_blank. $status . $user_id . $use_real_name . $user_name_filter . $portal_filter;
627 $user_array = get_register_value('user_array', $key_name);
630 if(empty($user_array)) {
631 $db = DBManagerFactory::getInstance();
632 $temp_result = Array();
633 // Including deleted users for now.
634 if (empty($status)) {
635 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$portal_filter;
638 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
641 if (!empty($user_name_filter)) {
642 $user_name_filter = $db->quote($user_name_filter);
643 $query .= " AND user_name LIKE '$user_name_filter%' ";
645 if (!empty($user_id)) {
646 $query .= " OR id='{$user_id}'";
648 $query = $query.' ORDER BY user_name ASC';
649 $GLOBALS['log']->debug("get_user_array query: $query");
650 $result = $db->query($query, true, "Error filling in user array: ");
652 if ($add_blank==true) {
653 // Add in a blank row
654 $temp_result[''] = '';
657 // Get the id and the name.
658 while($row = $db->fetchByAssoc($result)) {
659 if($use_real_name == true || showFullName()) {
660 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
661 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
663 $temp_result[$row['id']] = $row['user_name'];
666 $temp_result[$row['id']] = $row['user_name'];
670 $user_array = $temp_result;
673 set_register_value('user_array', $key_name, $temp_result);
683 * uses a different query to return a list of users than get_user_array()
684 * Used from QuickSearch.php
685 * @param args string where clause entry
686 * @return array Array of Users' details that match passed criteria
688 function getUserArrayFromFullName($args, $hide_portal_users = false) {
690 $db = DBManagerFactory::getInstance();
692 // jmorais@dri - Bug #51411
694 // Refactor the code responsible for parsing supplied $args, this way we
695 // ensure that if $args has at least one space (after trim), the $inClause
696 // will be composed by several clauses ($inClauses) inside parenthesis.
698 // Ensuring that operator precedence is respected, and avoiding
699 // inactive/deleted users to be retrieved.
702 if (strpos($args, ' ')) {
703 $inClauses = array();
705 $argArray = explode(' ', $args);
706 foreach ($argArray as $arg) {
707 $arg = $db->quote($arg);
708 $inClauses[] = "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
711 $inClause = '(' . implode('OR ', $inClauses) . ')';
714 $args = $db->quote($args);
715 $inClause = "(first_name LIKE '{$args}%' OR last_name LIKE '{$args}%')";
719 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
720 if ( $hide_portal_users ) {
721 $query .= " portal_only=0 AND ";
724 $query .= " ORDER BY last_name ASC";
726 $r = $db->query($query);
728 while($a = $db->fetchByAssoc($r)) {
729 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
737 * based on user pref then system pref
739 function showFullName() {
740 global $sugar_config;
741 global $current_user;
742 static $showFullName = null;
744 if (is_null($showFullName)) {
745 $sysPref = !empty($sugar_config['use_real_names']);
746 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
748 if($userPref != null) {
749 $showFullName = ($userPref == 'on');
751 $showFullName = $sysPref;
755 return $showFullName;
758 function clean($string, $maxLength)
760 $string = substr($string, 0, $maxLength);
761 return escapeshellcmd($string);
765 * Copy the specified request variable to the member variable of the specified object.
766 * Do no copy if the member variable is already set.
767 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
768 * All Rights Reserved.
769 * Contributor(s): ______________________________________..
771 function safe_map($request_var, & $focus, $always_copy = false)
773 safe_map_named($request_var, $focus, $request_var, $always_copy);
777 * Copy the specified request variable to the member variable of the specified object.
778 * Do no copy if the member variable is already set.
779 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
780 * All Rights Reserved.
781 * Contributor(s): ______________________________________..
783 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
785 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
786 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
787 $focus->$member_var = $_REQUEST[$request_var];
792 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
794 * @param string $language specific language to load
795 * @return array lang strings
797 function return_app_list_strings_language($language)
799 global $app_list_strings;
800 global $sugar_config;
802 $cache_key = 'app_list_strings.'.$language;
804 // Check for cached value
805 $cache_entry = sugar_cache_retrieve($cache_key);
806 if(!empty($cache_entry))
811 $default_language = $sugar_config['default_language'];
812 $temp_app_list_strings = $app_list_strings;
815 if ($language != 'en_us') {
818 if ($default_language != 'en_us' && $language != $default_language) {
819 $langs[] = $default_language;
821 $langs[] = $language;
823 $app_list_strings_array = array();
825 foreach ( $langs as $lang ) {
826 $app_list_strings = array();
827 if(file_exists("include/language/$lang.lang.php")) {
828 include("include/language/$lang.lang.php");
829 $GLOBALS['log']->info("Found language file: $lang.lang.php");
831 if(file_exists("include/language/$lang.lang.override.php")) {
832 include("include/language/$lang.lang.override.php");
833 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
835 if(file_exists("include/language/$lang.lang.php.override")) {
836 include("include/language/$lang.lang.php.override");
837 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
840 $app_list_strings_array[] = $app_list_strings;
843 $app_list_strings = array();
844 foreach ( $app_list_strings_array as $app_list_strings_item ) {
845 $app_list_strings = sugarLangArrayMerge($app_list_strings, $app_list_strings_item);
848 foreach ( $langs as $lang ) {
849 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
850 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
851 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
853 if(file_exists("custom/include/language/$lang.lang.php")) {
854 include("custom/include/language/$lang.lang.php");
855 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
859 if(!isset($app_list_strings)) {
860 $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");
864 $return_value = $app_list_strings;
865 $app_list_strings = $temp_app_list_strings;
867 sugar_cache_put($cache_key, $return_value);
869 return $return_value;
873 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
874 * $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.
875 * @param file string the language that you want include,
876 * @param app_list_strings array the golbal strings
880 function _mergeCustomAppListStrings($file , $app_list_strings){
881 $app_list_strings_original = $app_list_strings;
882 unset($app_list_strings);
883 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
884 // This way, language file can add items to save specific standard codelist from being overwritten
885 $exemptDropdowns = array();
887 if(!isset($app_list_strings) || !is_array($app_list_strings)){
888 return $app_list_strings_original;
890 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
892 // FG - bug 45525 - Specific codelists must NOT be overwritten
893 $exemptDropdowns[] = "moduleList";
894 $exemptDropdowns[] = "moduleListSingular";
895 $exemptDropdowns = array_merge($exemptDropdowns, getTypeDisplayList());
897 foreach($app_list_strings as $key=>$value)
899 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
901 unset($app_list_strings_original["$key"]);
904 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
905 return $app_list_strings;
909 * This function retrieves an application language file and returns the array of strings included.
911 * @param string $language specific language to load
912 * @return array lang strings
914 function return_application_language($language)
916 global $app_strings, $sugar_config;
918 $cache_key = 'app_strings.'.$language;
920 // Check for cached value
921 $cache_entry = sugar_cache_retrieve($cache_key);
922 if(!empty($cache_entry))
927 $temp_app_strings = $app_strings;
928 $default_language = $sugar_config['default_language'];
931 if ($language != 'en_us') {
934 if ($default_language != 'en_us' && $language != $default_language) {
935 $langs[] = $default_language;
938 $langs[] = $language;
940 $app_strings_array = array();
942 foreach ( $langs as $lang ) {
943 $app_strings = array();
944 if(file_exists("include/language/$lang.lang.php")) {
945 include("include/language/$lang.lang.php");
946 $GLOBALS['log']->info("Found language file: $lang.lang.php");
948 if(file_exists("include/language/$lang.lang.override.php")) {
949 include("include/language/$lang.lang.override.php");
950 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
952 if(file_exists("include/language/$lang.lang.php.override")) {
953 include("include/language/$lang.lang.php.override");
954 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
956 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
957 include("custom/application/Ext/Language/$lang.lang.ext.php");
958 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
960 if(file_exists("custom/include/language/$lang.lang.php")) {
961 include("custom/include/language/$lang.lang.php");
962 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
964 $app_strings_array[] = $app_strings;
967 $app_strings = array();
968 foreach ( $app_strings_array as $app_strings_item ) {
969 $app_strings = sugarLangArrayMerge($app_strings, $app_strings_item);
972 if(!isset($app_strings)) {
973 $GLOBALS['log']->fatal("Unable to load the application language strings");
977 // If we are in debug mode for translating, turn on the prefix now!
978 if(!empty($sugar_config['translation_string_prefix']))
980 foreach($app_strings as $entry_key=>$entry_value) {
981 $app_strings[$entry_key] = $language.' '.$entry_value;
984 if(isset($_SESSION['show_deleted'])) {
985 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
986 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
987 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
988 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
991 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
993 $return_value = $app_strings;
994 $app_strings = $temp_app_strings;
996 sugar_cache_put($cache_key, $return_value);
998 return $return_value;
1002 * This function retrieves a module's language file and returns the array of strings included.
1004 * @param string $language specific language to load
1005 * @param string $module module name to load strings for
1006 * @param bool $refresh optional, true if you want to rebuild the language strings
1007 * @return array lang strings
1009 function return_module_language($language, $module, $refresh=false)
1011 global $mod_strings;
1012 global $sugar_config;
1013 global $currentModule;
1015 // Jenny - Bug 8119: Need to check if $module is not empty
1016 if (empty($module)) {
1017 $stack = debug_backtrace();
1018 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
1024 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1025 // Check for cached value
1026 $cache_entry = sugar_cache_retrieve($cache_key);
1027 if(!empty($cache_entry) && is_array($cache_entry))
1029 return $cache_entry;
1032 // Store the current mod strings for later
1033 $temp_mod_strings = $mod_strings;
1034 $loaded_mod_strings = array();
1035 $language_used = $language;
1036 $default_language = $sugar_config['default_language'];
1038 if(empty($language)) {
1039 $language = $default_language;
1042 // Bug 21559 - So we can get all the strings defined in the template, refresh
1043 // the vardefs file if the cached language file doesn't exist.
1044 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1045 && !empty($GLOBALS['beanList'][$module])){
1046 $object = BeanFactory::getObjectName($module);
1047 VardefManager::refreshVardefs($module,$object);
1050 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1052 // cn: bug 6048 - merge en_us with requested language
1053 if($language != $sugar_config['default_language'])
1054 $loaded_mod_strings = sugarLangArrayMerge(
1055 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1059 // Load in en_us strings by default
1060 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1061 $loaded_mod_strings = sugarLangArrayMerge(
1062 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1066 // If we are in debug mode for translating, turn on the prefix now!
1067 if($sugar_config['translation_string_prefix']) {
1068 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1069 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1073 $return_value = $loaded_mod_strings;
1074 if(!isset($mod_strings)){
1075 $mod_strings = $return_value;
1078 $mod_strings = $temp_mod_strings;
1080 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1081 sugar_cache_put($cache_key, $return_value);
1082 return $return_value;
1086 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1087 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1088 * All Rights Reserved.
1089 * Contributor(s): ______________________________________..
1090 * If you are using the current language, do not call this function unless you are loading it for the first time */
1091 function return_mod_list_strings_language($language,$module) {
1092 global $mod_list_strings;
1093 global $sugar_config;
1094 global $currentModule;
1096 $cache_key = "mod_list_str_lang.".$language.$module;
1098 // Check for cached value
1099 $cache_entry = sugar_cache_retrieve($cache_key);
1100 if(!empty($cache_entry))
1102 return $cache_entry;
1105 $language_used = $language;
1106 $temp_mod_list_strings = $mod_list_strings;
1107 $default_language = $sugar_config['default_language'];
1109 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1110 return $mod_list_strings;
1113 // cn: bug 6351 - include en_us if file langpack not available
1114 // cn: bug 6048 - merge en_us with requested language
1115 include("modules/$module/language/en_us.lang.php");
1116 $en_mod_list_strings = array();
1117 if($language_used != $default_language)
1118 $en_mod_list_strings = $mod_list_strings;
1120 if(file_exists("modules/$module/language/$language.lang.php")) {
1121 include("modules/$module/language/$language.lang.php");
1124 if(file_exists("modules/$module/language/$language.lang.override.php")){
1125 include("modules/$module/language/$language.lang.override.php");
1128 if(file_exists("modules/$module/language/$language.lang.php.override")){
1129 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1130 include("modules/$module/language/$language.lang.php.override");
1133 // cn: bug 6048 - merge en_us with requested language
1134 $mod_list_strings = sugarLangArrayMerge($en_mod_list_strings, $mod_list_strings);
1136 // if we still don't have a language pack, then log an error
1137 if(!isset($mod_list_strings)) {
1138 $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})");
1142 $return_value = $mod_list_strings;
1143 $mod_list_strings = $temp_mod_list_strings;
1145 sugar_cache_put($cache_key, $return_value);
1146 return $return_value;
1150 /** This function retrieves a theme's language file and returns the array of strings included.
1151 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1152 * All Rights Reserved.
1153 * Contributor(s): ______________________________________..
1155 function return_theme_language($language, $theme)
1157 global $mod_strings, $sugar_config, $current_language;
1159 $language_used = $language;
1160 $default_language = $sugar_config['default_language'];
1162 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1163 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1164 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1166 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1167 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";
1168 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1170 if(!isset($theme_strings))
1172 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1173 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1174 $language_used = $default_language;
1177 if(!isset($theme_strings))
1179 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1183 // If we are in debug mode for translating, turn on the prefix now!
1184 if($sugar_config['translation_string_prefix'])
1186 foreach($theme_strings as $entry_key=>$entry_value)
1188 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1192 return $theme_strings;
1197 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1198 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1199 * All Rights Reserved.
1200 * Contributor(s): ______________________________________..
1202 function return_session_value_or_default($varname, $default)
1204 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1206 return $_SESSION[$varname];
1213 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1214 * 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.
1215 * @param &$where_clauses - The array to append the clause to
1216 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1217 * @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.
1218 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1219 * All Rights Reserved.
1220 * Contributor(s): ______________________________________..
1222 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1224 if($SQL_name == null)
1226 $SQL_name = $variable_name;
1229 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1231 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1236 * Generate the appropriate SQL based on the where clauses.
1237 * @param $where_clauses - An Array of individual where clauses stored as strings
1238 * @returns string where_clause - The final SQL where clause to be executed.
1239 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1240 * All Rights Reserved.
1241 * Contributor(s): ______________________________________..
1243 function generate_where_statement($where_clauses)
1246 foreach($where_clauses as $clause)
1253 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1258 * determines if a passed string matches the criteria for a Sugar GUID
1259 * @param string $guid
1260 * @return bool False on failure
1262 function is_guid($guid) {
1263 if(strlen($guid) != 36) {
1267 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1276 * A temporary method of generating GUIDs of the correct format for our DB.
1277 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1279 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1280 * All Rights Reserved.
1281 * Contributor(s): ______________________________________..
1283 function create_guid()
1285 $microTime = microtime();
1286 list($a_dec, $a_sec) = explode(" ", $microTime);
1288 $dec_hex = dechex($a_dec* 1000000);
1289 $sec_hex = dechex($a_sec);
1291 ensure_length($dec_hex, 5);
1292 ensure_length($sec_hex, 6);
1296 $guid .= create_guid_section(3);
1298 $guid .= create_guid_section(4);
1300 $guid .= create_guid_section(4);
1302 $guid .= create_guid_section(4);
1305 $guid .= create_guid_section(6);
1311 function create_guid_section($characters)
1314 for($i=0; $i<$characters; $i++)
1316 $return .= dechex(mt_rand(0,15));
1321 function ensure_length(&$string, $length)
1323 $strlen = strlen($string);
1324 if($strlen < $length)
1326 $string = str_pad($string,$length,"0");
1328 else if($strlen > $length)
1330 $string = substr($string, 0, $length);
1334 function microtime_diff($a, $b) {
1335 list($a_dec, $a_sec) = explode(" ", $a);
1336 list($b_dec, $b_sec) = explode(" ", $b);
1337 return $b_sec - $a_sec + $b_dec - $a_dec;
1340 // check if Studio is displayed.
1341 function displayStudioForCurrentUser()
1343 global $current_user;
1344 if ( $current_user->isAdmin() ) {
1354 function displayWorkflowForCurrentUser()
1356 $_SESSION['display_workflow_for_user'] = false;
1360 // return an array with all modules where the user is an admin.
1361 function get_admin_modules_for_user($user) {
1362 $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");
1369 return($user->getDeveloperModules());
1373 function get_workflow_admin_modules_for_user($user){
1374 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1375 return $_SESSION['get_workflow_admin_modules_for_user'];
1379 $workflow_mod_list = array();
1380 foreach($moduleList as $module){
1381 $workflow_mod_list[$module] = $module;
1384 // This list is taken from teh previous version of workflow_utils.php
1385 $workflow_mod_list['Tasks'] = "Tasks";
1386 $workflow_mod_list['Calls'] = "Calls";
1387 $workflow_mod_list['Meetings'] = "Meetings";
1388 $workflow_mod_list['Notes'] = "Notes";
1389 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1390 $workflow_mod_list['Leads'] = "Leads";
1391 $workflow_mod_list['Opportunities'] = "Opportunities";
1394 $workflow_admin_modules = array();
1396 return $workflow_admin_modules;
1398 $actions = ACLAction::getUserActions($user->id);
1399 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1400 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1401 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1402 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1404 foreach ($workflow_mod_list as $key=>$val) {
1405 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1406 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1407 ($user->isDeveloperForModule($key))) {
1408 $workflow_admin_modules[$key] = $val;
1411 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1412 return ($workflow_admin_modules);
1415 // Check if user is admin for at least one module.
1416 function is_admin_for_any_module($user) {
1420 if($user->isAdmin()) {
1427 // Check if user is admin for a specific module.
1428 function is_admin_for_module($user,$module) {
1429 if (!isset($user)) {
1432 if ($user->isAdmin()) {
1440 * Check if user id belongs to a system admin.
1441 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1442 * All Rights Reserved.
1443 * Contributor(s): ______________________________________..
1445 function is_admin($user) {
1450 return $user->isAdmin();
1454 * Return the display name for a theme if it exists.
1455 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1456 * All Rights Reserved.
1457 * Contributor(s): ______________________________________..
1459 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1461 function get_theme_display($theme)
1463 return SugarThemeRegistry::get($theme)->name;
1467 * Return an array of directory names.
1468 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1469 * All Rights Reserved.
1470 * Contributor(s): ______________________________________..
1472 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1474 function get_themes()
1476 return SugarThemeRegistry::availableThemes();
1480 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1481 * Create HTML to display select options in a dropdown list. To be used inside
1482 * of a select statement in a form.
1483 * param $option_list - the array of strings to that contains the option list
1484 * param $selected - the string which contains the default value
1485 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1486 * All Rights Reserved.
1487 * Contributor(s): ______________________________________..
1489 function get_select_options ($option_list, $selected) {
1490 return get_select_options_with_id($option_list, $selected);
1494 * Create HTML to display select options in a dropdown list. To be used inside
1495 * 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.
1496 * param $option_list - the array of strings to that contains the option list
1497 * param $selected - the string which contains the default value
1498 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1499 * All Rights Reserved.
1500 * Contributor(s): ______________________________________..
1502 function get_select_options_with_id ($option_list, $selected_key) {
1503 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1508 * Create HTML to display select options in a dropdown list. To be used inside
1509 * 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.
1510 * param $label_list - the array of strings to that contains the option list
1511 * param $key_list - the array of strings to that contains the values list
1512 * param $selected - the string which contains the default value
1513 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1514 * All Rights Reserved.
1515 * Contributor(s): ______________________________________..
1517 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1518 global $app_strings;
1519 $select_options = "";
1521 //for setting null selection values to human readable --None--
1522 $pattern = "/'0?'></";
1523 $replacement = "''>".$app_strings['LBL_NONE']."<";
1525 $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
1528 if (empty($key_list)) $key_list = array();
1529 //create the type dropdown domain and set the selected value if $opp value already exists
1530 foreach ($key_list as $option_key=>$option_value) {
1532 $selected_string = '';
1533 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1534 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1536 ($option_key != '' && $selected_key == $option_key)
1539 && (($selected_key == '' && !$massupdate) || $selected_key == '__SugarMassUpdateClearField__')
1541 || (is_array($selected_key) && in_array($option_key, $selected_key))
1543 $selected_string = 'selected ';
1546 $html_value = $option_key;
1548 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1550 $select_options = preg_replace($pattern, $replacement, $select_options);
1551 return $select_options;
1556 * Call this method instead of die().
1557 * We print the error message and then die with an appropriate
1560 function sugar_die($error_message, $exit_code = 1)
1564 echo $error_message;
1570 * Create javascript to clear values of all elements in a form.
1571 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1572 * All Rights Reserved.
1573 * Contributor(s): ______________________________________..
1575 function get_clear_form_js () {
1576 $the_script = <<<EOQ
1577 <script type="text/javascript" language="JavaScript">
1578 function clear_form(form) {
1579 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1580 if(typeof(form.advanced) != 'undefined'){
1581 newLoc += '&advanced=' + form.advanced.value;
1583 document.location.href= newLoc;
1592 * Create javascript to set the cursor focus to specific field in a form
1593 * when the screen is rendered. The field name is currently hardcoded into the
1595 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1596 * All Rights Reserved.
1597 * Contributor(s): ______________________________________..
1599 function get_set_focus_js () {
1600 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1601 $the_script = <<<EOQ
1602 <script type="text/javascript" language="JavaScript">
1604 function set_focus() {
1605 if (document.forms.length > 0) {
1606 for (i = 0; i < document.forms.length; i++) {
1607 for (j = 0; j < document.forms[i].elements.length; j++) {
1608 var field = document.forms[i].elements[j];
1609 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1610 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1612 if (field.type == "text") {
1629 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1630 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1631 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1632 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1633 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1634 * the first - so the array is sorted by the last given column first, then the one before ...
1635 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1636 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1637 * All Rights Reserved.
1638 * Contributor(s): ______________________________________..
1640 function array_csort() {
1641 $args = func_get_args();
1642 $marray = array_shift($args);
1645 $msortline = "return(array_multisort(";
1646 foreach ($args as $arg) {
1648 if (is_string($arg)) {
1649 foreach ($marray as $row) {
1650 $sortarr[$i][] = $row[$arg];
1653 $sortarr[$i] = $arg;
1655 $msortline .= "\$sortarr[".$i."],";
1657 $msortline .= "\$marray));";
1664 * Converts localized date format string to jscalendar format
1665 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1666 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1667 * All Rights Reserved.
1668 * Contributor(s): ______________________________________..
1670 function parse_calendardate($local_format) {
1671 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1672 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1673 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1680 function translate($string, $mod='', $selectedValue=''){
1681 //$test_start = microtime();
1682 //static $mod_strings_results = array();
1684 global $current_language;
1686 if(isset($_REQUEST['login_language'])){
1687 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1689 $mod_strings = return_module_language($current_language, $mod);
1691 echo "Language is <pre>" . $mod_strings . "</pre>";
1694 global $mod_strings;
1698 global $app_strings, $app_list_strings;
1700 if (isset($mod_strings[$string]))
1701 $returnValue = $mod_strings[$string];
1702 else if (isset($app_strings[$string]))
1703 $returnValue = $app_strings[$string];
1704 else if (isset($app_list_strings[$string]))
1705 $returnValue = $app_list_strings[$string];
1706 else if (isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1707 $returnValue = $app_list_strings['moduleList'][$string];
1710 //$test_end = microtime();
1712 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1714 // echo("translate results:");
1716 // $total_strings = 0;
1717 // foreach($mod_strings_results as $key=>$value)
1719 // echo("Module $key \t\t time $value \t\t<br>");
1720 // $total_time += $value;
1723 // echo("Total time: $total_time<br>");
1727 if(empty($returnValue)){
1731 // Bug 48996 - Custom enums with '0' value were not returning because of empty check
1732 // Added a numeric 0 checker to the conditional to allow 0 value indexed to pass
1733 if(is_array($returnValue) && (!empty($selectedValue) || (is_numeric($selectedValue) && $selectedValue == 0)) && isset($returnValue[$selectedValue]) ){
1734 return $returnValue[$selectedValue];
1737 return $returnValue;
1740 function unTranslateNum($num) {
1742 static $num_grp_sep;
1743 global $current_user, $sugar_config;
1745 if($dec_sep == null) {
1746 $user_dec_sep = $current_user->getPreference('dec_sep');
1747 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1749 if($num_grp_sep == null) {
1750 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1751 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1754 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1755 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1760 function add_http($url) {
1761 if(!preg_match("@://@i", $url)) {
1763 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1767 return "{$scheme}://{$url}";
1774 * returns a default array of XSS tags to clean
1777 function getDefaultXssTags() {
1779 "applet" => "applet",
1784 "frameset" => "frameset",
1785 "iframe" => "iframe",
1786 "import" => "\?import",
1789 "object" => "object",
1790 "script" => "script",
1794 $ret = base64_encode(serialize($tmp));
1800 * Remove potential xss vectors from strings
1801 * @param string str String to search for XSS attack vectors
1805 function remove_xss($str)
1807 return SugarCleaner::cleanHtml($str, false);
1811 * Detects typical XSS attack patterns
1813 * @param string str String to search for XSS attack vectors
1814 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1815 * @return array Array of matches, empty on clean string
1817 function clean_xss($str, $cleanImg=true) {
1818 global $sugar_config;
1820 if(empty($sugar_config['email_xss']))
1821 $sugar_config['email_xss'] = getDefaultXssTags();
1823 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1825 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1826 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1827 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1828 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1830 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1831 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1832 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1833 $css_url = '#url\(.*\.\w+\)#';
1835 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1837 $tagmatches = array();
1839 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1840 foreach($tagmatches[1] as $no => $tag) {
1841 if(in_array($tag, $xsstags)) {
1842 // dangerous tag - take out whole
1843 $matches[] = $tagmatches[0][$no];
1846 $attrmatch = array();
1847 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1848 if(!empty($attrmatch[0])) {
1849 $matches = array_merge($matches, $attrmatch[0]);
1853 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1856 $matches = array_merge($matches,
1857 xss_check_pattern($imgsrc_regex, $str)
1861 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1862 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1864 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1865 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1866 // normalize whitelist
1867 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1868 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1871 foreach($cssUrlMatches[0] as $match) {
1872 $domain = strtolower(substr(strstr($match, "://"), 3));
1873 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1875 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1876 $matches[] = $match;
1881 $matches = array_merge($matches, $cssUrlMatches[0]);
1888 * Helper function used by clean_xss() to parse for known-bad vectors
1889 * @param string pattern Regex pattern to use
1890 * @param string str String to parse for badness
1893 function xss_check_pattern($pattern, $str) {
1894 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1899 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1901 * @param string $str
1902 * @param string $filter which corresponds to a regular expression to use; choices are:
1903 * "STANDARD" ( default )
1913 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1915 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1917 global $sugar_config;
1920 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1921 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1922 "FILE" => '#[^A-Z0-9\-_\.]#i',
1923 "NUMBER" => '#[^0-9\-]#i',
1924 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1925 "PATH_NO_URL" => '#://#i',
1926 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1927 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1928 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1929 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1932 if (preg_match($filters[$filter], $str)) {
1933 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1934 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1936 if ( $dieOnBadData ) {
1937 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1946 function clean_special_arguments() {
1947 if(isset($_SERVER['PHP_SELF'])) {
1948 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1950 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1951 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1952 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1953 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1954 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1955 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1956 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1957 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1958 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1959 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1960 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1961 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1962 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1963 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1964 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1965 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1966 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1967 clean_superglobals('offset', 'ALPHANUM');
1968 clean_superglobals('return_action');
1969 clean_superglobals('return_module');
1974 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1976 function clean_superglobals($key, $filter = 'STANDARD') {
1977 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1978 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1979 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1982 function set_superglobals($key, $val){
1984 $_POST[$key] = $val;
1985 $_REQUEST[$key] = $val;
1988 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1989 function clean_incoming_data() {
1990 global $sugar_config;
1991 global $RAW_REQUEST;
1993 if(get_magic_quotes_gpc()) {
1994 // magic quotes screw up data, we'd have to clean up
1995 $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1997 $RAW_REQUEST = $_REQUEST;
2000 if (get_magic_quotes_gpc() == 1) {
2001 $req = array_map("preprocess_param", $_REQUEST);
2002 $post = array_map("preprocess_param", $_POST);
2003 $get = array_map("preprocess_param", $_GET);
2006 $req = array_map("securexss", $_REQUEST);
2007 $post = array_map("securexss", $_POST);
2008 $get = array_map("securexss", $_GET);
2011 // PHP cannot stomp out superglobals reliably
2012 foreach($post as $k => $v) { $_POST[$k] = $v; }
2013 foreach($get as $k => $v) { $_GET[$k] = $v; }
2014 foreach($req as $k => $v) {
2017 //ensure the keys are safe as well. If mbstring encoding translation is on, the post keys don't
2018 //get translated, so scrub the data but don't die
2019 if(ini_get('mbstring.encoding_translation')==='1'){
2020 securexsskey($k,false);
2022 securexsskey($k,true);
2026 // Any additional variables that need to be cleaned should be added here
2027 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
2028 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
2029 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
2030 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
2031 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
2032 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
2033 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
2034 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
2035 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
2036 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
2037 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
2038 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
2039 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
2041 if(isset($_REQUEST['lvso'])){
2042 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
2044 // Clean "offset" and "order_by" parameters in URL
2045 foreach ($_REQUEST as $key => $val) {
2046 if (str_end($key, "_offset")) {
2047 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
2048 set_superglobals($key, $_REQUEST[$key]);
2050 elseif (str_end($key, "_ORDER_BY")) {
2051 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2052 set_superglobals($key, $_REQUEST[$key]);
2060 // Returns TRUE if $str begins with $begin
2061 function str_begin($str, $begin) {
2062 return (substr($str, 0, strlen($begin)) == $begin);
2065 // Returns TRUE if $str ends with $end
2066 function str_end($str, $end) {
2067 return (substr($str, strlen($str) - strlen($end)) == $end);
2070 function securexss($value) {
2071 if(is_array($value)){
2073 foreach($value as $key=>$val){
2074 $new[$key] = securexss($val);
2078 static $xss_cleanup= array(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2079 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2080 $value = preg_replace('/javascript:/i', 'java script:', $value);
2081 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2084 function securexsskey($value, $die=true){
2085 global $sugar_config;
2087 preg_match('/[\'"<>]/', $value, $matches);
2088 if(!empty($matches)){
2090 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2092 unset($_REQUEST[$value]);
2093 unset($_POST[$value]);
2094 unset($_GET[$value]);
2099 function preprocess_param($value){
2100 if(is_string($value)){
2101 if(get_magic_quotes_gpc() == 1){
2102 $value = stripslashes($value);
2105 $value = securexss($value);
2107 else if (is_array($value)){
2108 foreach ($value as $key => $element) {
2109 $value[$key] = preprocess_param($element);
2116 function cleanup_slashes($value)
2118 if(is_string($value)) return stripslashes($value);
2123 function set_register_value($category, $name, $value){
2124 return sugar_cache_put("{$category}:{$name}", $value);
2127 function get_register_value($category,$name){
2128 return sugar_cache_retrieve("{$category}:{$name}");
2131 function clear_register_value($category,$name){
2132 return sugar_cache_clear("{$category}:{$name}");
2134 // this function cleans id's when being imported
2135 function convert_id($string)
2137 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2139 // single quotes are essential here,
2140 // or alternative escape all $ as \$
2142 'return ord($matches[0]);'
2147 * @deprecated use SugarTheme::getImage()
2149 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2151 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2154 * @deprecated use SugarTheme::getImageURL()
2156 function getImagePath($image_name)
2158 return SugarThemeRegistry::current()->getImageURL($image_name);
2161 function getWebPath($relative_path){
2162 //if it has a :// then it isn't a relative path
2163 if(substr_count($relative_path, '://') > 0) return $relative_path;
2164 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2165 return $relative_path;
2168 function getVersionedPath($path, $additional_attrs='')
2170 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2171 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2172 if(inDeveloperMode()) {
2174 if(empty($rand)) $rand = mt_rand();
2179 if(is_array($additional_attrs)) {
2180 $additional_attrs = join("|",$additional_attrs);
2182 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2183 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2184 // remove / - it confuses some parsers
2185 $str = strtr($str, '/+', '-_');
2186 if(empty($path)) return $str;
2188 return $path . "?v=$str";
2191 function getVersionedScript($path, $additional_attrs='')
2193 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2196 function getJSPath($relative_path, $additional_attrs='')
2198 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2199 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2202 function getSWFPath($relative_path, $additional_params=''){
2203 $path = $relative_path;
2204 if (!empty($additional_params)){
2205 $path .= '?' . $additional_params;
2207 if (defined('TEMPLATE_URL')){
2208 $path = TEMPLATE_URL . '/' . $path;
2217 function getSQLDate($date_str)
2219 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2221 if ( strlen($match[2]) == 1)
2223 $match[2] = "0".$match[2];
2225 if ( strlen($match[1]) == 1)
2227 $match[1] = "0".$match[1];
2229 return "{$match[3]}-{$match[1]}-{$match[2]}";
2231 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2233 if ( strlen($match[2]) == 1)
2235 $match[2] = "0".$match[2];
2237 if ( strlen($match[1]) == 1)
2239 $match[1] = "0".$match[1];
2241 return "{$match[3]}-{$match[1]}-{$match[2]}";
2249 function clone_history(&$db, $from_id,$to_id, $to_type)
2254 require_once('include/upload_file.php');
2255 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2257 $location=array('Email'=>"modules/Emails/Email.php",
2258 'Call'=>"modules/Calls/Call.php",
2259 'Meeting'=>"modules/Meetings/Meeting.php",
2260 'Note'=>"modules/Notes/Note.php",
2261 'Tasks'=>"modules/Tasks/Task.php",
2265 foreach($tables as $table=>$bean_class)
2268 if (!class_exists($bean_class))
2270 require_once($location[$bean_class]);
2273 $bProcessingNotes=false;
2274 if ($table=='notes')
2276 $bProcessingNotes=true;
2278 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2279 $results = $db->query($query);
2280 while($row = $db->fetchByAssoc($results))
2282 //retrieve existing record.
2283 $bean= new $bean_class();
2284 $bean->retrieve($row['id']);
2285 //process for new instance.
2286 if ($bProcessingNotes)
2288 $old_note_id=$row['id'];
2289 $old_filename=$bean->filename;
2292 $bean->parent_id=$to_id;
2293 $bean->parent_type=$to_type;
2294 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2296 $bean->contact_id=$to_id;
2298 $bean->update_date_modified = false;
2299 $bean->update_modified_by = false;
2300 if(isset($bean->date_modified))
2301 $bean->date_modified = $timedate->to_db($bean->date_modified);
2302 if(isset($bean->date_entered))
2303 $bean->date_entered = $timedate->to_db($bean->date_entered);
2305 $new_id=$bean->save();
2307 //duplicate the file now. for notes.
2308 if ($bProcessingNotes && !empty($old_filename))
2310 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2312 //reset the values needed for attachment duplication.
2319 function values_to_keys($array)
2321 $new_array = array();
2322 if(!is_array($array))
2326 foreach($array as $arr){
2327 $new_array[$arr] = $arr;
2332 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2334 foreach($tables as $table)
2337 if ($table == 'emails_beans') {
2338 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2340 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2342 $results = $db->query($query);
2343 while($row = $db->fetchByAssoc($results))
2345 $query = "INSERT INTO $table ";
2348 $row[$from_column] = $to_id;
2349 $row['id'] = create_guid();
2350 if ($table=='emails_beans') {
2351 $row['bean_module'] =='Contacts';
2354 foreach($row as $name=>$value)
2360 $values .= "'$value'";
2363 $names .= ', '. $name;
2364 $values .= ", '$value'";
2367 $query .= "($names) VALUES ($values)";
2373 function get_unlinked_email_query($type, $bean) {
2374 global $current_user;
2376 $return_array['select']='SELECT emails.id ';
2377 $return_array['from']='FROM emails ';
2378 $return_array['where']="";
2379 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2381 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2382 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2383 where eear.deleted=0 and eear.email_id not in
2384 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2385 ) derivedemails on derivedemails.email_id = emails.id";
2386 $return_array['join_tables'][0] = '';
2388 if (isset($type) and !empty($type['return_as_array'])) {
2389 return $return_array;
2392 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2395 function get_emails_by_assign_or_link($params)
2397 $relation = $params['link'];
2398 $bean = $GLOBALS['app']->controller->bean;
2399 if(empty($bean->$relation)) {
2400 $bean->load_relationship($relation);
2402 if(empty($bean->$relation)) {
2403 $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
2406 $rel_module = $bean->$relation->getRelatedModuleName();
2407 $rel_join = $bean->$relation->getJoin(array(
2408 'join_table_alias' => 'link_bean',
2409 'join_table_link_alias' => 'linkt',
2411 $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
2412 $return_array['select']='SELECT DISTINCT emails.id ';
2413 $return_array['from'] = "FROM emails ";
2414 $return_array['join'] = " INNER JOIN (".
2415 // directly assigned emails
2416 "select eb.email_id, 'direct' source FROM emails_beans eb where eb.bean_module = '{$bean->module_dir}' AND eb.bean_id = '{$bean->id}' AND eb.deleted=0 ".
2418 // Assigned to contacts
2419 "select DISTINCT eb.email_id, 'contact' source FROM emails_beans eb
2420 $rel_join AND link_bean.id = eb.bean_id
2421 where eb.bean_module = '$rel_module' AND eb.deleted=0".
2423 // Related by directly by email
2424 "select DISTINCT eear.email_id, 'relate' source from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2425 ON eabr.bean_id ='{$bean->id}' AND eabr.bean_module = '{$bean->module_dir}' AND
2426 eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0".
2428 // Related by email to linked contact
2429 "select DISTINCT eear.email_id, 'relate_contact' source FROM emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2430 ON eabr.email_address_id=eear.email_address_id AND eabr.bean_module = '$rel_module' AND eabr.deleted=0
2431 $rel_join AND link_bean.id = eabr.bean_id
2432 where eear.deleted=0".
2433 ") email_ids ON emails.id=email_ids.email_id ";
2434 $return_array['where']=" WHERE emails.deleted=0 ";
2436 //$return_array['join'] = '';
2437 $return_array['join_tables'][0] = '';
2439 if($bean->object_name == "Case" && !empty($bean->case_number)) {
2440 $where = str_replace("%1", $bean->case_number, $bean->getEmailSubjectMacro());
2441 $return_array["where"] .= "\n AND (email_ids.source = 'direct' OR emails.name LIKE '%$where%')";
2444 return $return_array;
2448 * Check to see if the number is empty or non-zero
2452 function number_empty($value)
2454 return empty($value) && $value != '0';
2457 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2460 require_once($beanFiles[$bean_name]);
2461 $focus = new $bean_name();
2462 $user_array = array();
2464 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2465 $user_array = get_register_value('select_array', $key );
2469 $db = DBManagerFactory::getInstance();
2471 $temp_result = Array();
2472 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2476 $query .= $where." AND ";
2479 $query .= " {$focus->table_name}.deleted=0";
2481 if ( $order_by != '')
2483 $query .= " order by {$focus->table_name}.{$order_by}";
2486 $GLOBALS['log']->debug("get_user_array query: $query");
2487 $result = $db->query($query, true, "Error filling in user array: ");
2489 if ($add_blank==true){
2490 // Add in a blank row
2491 if($blank_is_none == true) { // set 'blank row' to "--None--"
2492 global $app_strings;
2493 $temp_result[''] = $app_strings['LBL_NONE'];
2495 $temp_result[''] = '';
2499 // Get the id and the name.
2500 while($row = $db->fetchByAssoc($result))
2502 $temp_result[$row['id']] = $row['display'];
2505 $user_array = $temp_result;
2506 set_register_value('select_array', $key ,$temp_result);
2515 * @param unknown_type $listArray
2517 // function parse_list_modules
2518 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2519 function parse_list_modules(&$listArray)
2521 global $modListHeader;
2522 $returnArray = array();
2524 foreach($listArray as $optionName => $optionVal)
2526 if(array_key_exists($optionName, $modListHeader))
2528 $returnArray[$optionName] = $optionVal;
2531 // special case for projects
2532 if(array_key_exists('Project', $modListHeader))
2534 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2537 $acldenied = ACLController::disabledModuleList($listArray,false);
2538 foreach($acldenied as $denied){
2539 unset($returnArray[$denied]);
2541 asort($returnArray);
2543 return $returnArray;
2546 function display_notice($msg = false){
2547 global $error_notice;
2548 //no error notice - lets just display the error to the user
2549 if(!isset($error_notice)){
2550 echo '<br>'.$msg . '<br>';
2552 $error_notice .= $msg . '<br>';
2556 /* checks if it is a number that at least has the plus at the beginning.
2558 function skype_formatted($number){
2559 //kbrill - BUG #15375
2560 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2563 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2565 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2568 function format_skype($number) {
2569 return preg_replace('/[^\+0-9]/','',$number);
2572 function insert_charset_header() {
2573 header('Content-Type: text/html; charset=UTF-8');
2576 function getCurrentURL()
2579 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2584 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2588 function javascript_escape($str) {
2591 for($i = 0; $i < strlen($str); $i++) {
2593 if(ord(substr($str, $i, 1))==10){
2595 }elseif(ord(substr($str, $i, 1))==13){
2599 $new_str .= $str{$i};
2603 $new_str = str_replace("'", "\\'", $new_str);
2608 function js_escape($str, $keep=true){
2609 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2612 $str = javascript_escape($str);
2615 $str = str_replace("'", " ", $str);
2616 $str = str_replace('"', " ", $str);
2621 //end function js_escape
2624 function br2nl($str) {
2625 $regex = "#<[^>]+br.+?>#i";
2626 preg_match_all($regex, $str, $matches);
2628 foreach($matches[0] as $match) {
2629 $str = str_replace($match, "<br>", $str);
2632 $brs = array('<br>','<br/>', '<br />');
2633 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2634 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2635 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2636 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2642 * Private helper function for displaying the contents of a given variable.
2643 * This function is only intended to be used for SugarCRM internal development.
2644 * The ppd stands for Pre Print Die.
2646 function _ppd($mixed)
2652 * Private helper function for displaying the contents of a given variable in
2653 * the Logger. This function is only intended to be used for SugarCRM internal
2654 * development. The pp stands for Pre Print.
2655 * @param $mixed var to print_r()
2656 * @param $die boolean end script flow
2657 * @param $displayStackTrace also show stack trace
2659 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2660 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2662 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2666 $mix = print_r($mixed, true); // send print_r() output to $mix
2667 $stack = debug_backtrace();
2669 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2670 $GLOBALS['log']->$loglevel($mix);
2671 if($displayStackTrace) {
2672 foreach($stack as $position) {
2673 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2677 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2678 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2686 * private helper function to quickly show the major, direct, field attributes of a given bean.
2687 * The ppf stands for Pre[formatted] Print Focus [object]
2688 * @param object bean The focus bean
2690 function _ppf($bean, $die=false) {
2696 * Private helper function for displaying the contents of a given variable.
2697 * This function is only intended to be used for SugarCRM internal development.
2698 * The pp stands for Pre Print.
2700 function _pp($mixed)
2705 * Private helper function for displaying the contents of a given variable.
2706 * This function is only intended to be used for SugarCRM internal development.
2707 * The pp stands for Pre Print.
2709 function _pstack_trace($mixed=NULL)
2714 * Private helper function for displaying the contents of a given variable.
2715 * This function is only intended to be used for SugarCRM internal development.
2716 * The pp stands for Pre Print Trace.
2718 function _ppt($mixed, $textOnly=false)
2723 * Private helper function for displaying the contents of a given variable.
2724 * This function is only intended to be used for SugarCRM internal development.
2725 * The pp stands for Pre Print Trace Die.
2727 function _pptd($mixed)
2732 * Private helper function for decoding javascript UTF8
2733 * This function is only intended to be used for SugarCRM internal development.
2735 function decodeJavascriptUTF8($str) {
2739 * Will check if a given PHP version string is supported (tested on this ver),
2740 * unsupported (results unknown), or invalid (something will break on this
2741 * ver). Do not pass in any pararameter to default to a check against the
2742 * current environment's PHP version.
2744 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2746 function check_php_version($sys_php_version = '') {
2747 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2748 // versions below $min_considered_php_version considered invalid by default,
2749 // versions equal to or above this ver will be considered depending
2750 // on the rules that follow
2751 $min_considered_php_version = '5.2.1';
2753 // only the supported versions,
2754 // should be mutually exclusive with $invalid_php_versions
2755 $supported_php_versions = array (
2756 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2759 // invalid versions above the $min_considered_php_version,
2760 // should be mutually exclusive with $supported_php_versions
2762 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2763 $invalid_php_versions = array('5.2.7');
2765 // default unsupported
2768 // versions below $min_considered_php_version are invalid
2769 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2773 // supported version check overrides default unsupported
2774 foreach($supported_php_versions as $ver) {
2775 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2781 // invalid version check overrides default unsupported
2782 foreach($invalid_php_versions as $ver) {
2783 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2789 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2790 //and the php version contains 'rh' characters
2791 if(strpos($sys_php_version, 'rh') !== false) {
2799 * Will check if a given IIS version string is supported (tested on this ver),
2800 * unsupported (results unknown), or invalid (something will break on this
2803 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2805 function check_iis_version($sys_iis_version = '') {
2807 $server_software = $_SERVER["SERVER_SOFTWARE"];
2809 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2810 $iis_version = $out[1][0];
2812 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2814 // versions below $min_considered_iis_version considered invalid by default,
2815 // versions equal to or above this ver will be considered depending
2816 // on the rules that follow
2817 $min_considered_iis_version = '6.0';
2819 // only the supported versions,
2820 // should be mutually exclusive with $invalid_iis_versions
2821 $supported_iis_versions = array ('6.0', '7.0',);
2822 $unsupported_iis_versions = array();
2823 $invalid_iis_versions = array('5.0',);
2825 // default unsupported
2828 // versions below $min_considered_iis_version are invalid
2829 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2833 // supported version check overrides default unsupported
2834 foreach($supported_iis_versions as $ver) {
2835 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2841 // unsupported version check overrides default unsupported
2842 foreach($unsupported_iis_versions as $ver) {
2843 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2849 // invalid version check overrides default unsupported
2850 foreach($invalid_iis_versions as $ver) {
2851 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2860 function pre_login_check(){
2861 global $action, $login_error;
2862 if(!empty($action)&& $action == 'Login'){
2864 if(!empty($login_error)){
2865 $login_error = htmlentities($login_error);
2866 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2867 $_SESSION['login_error'] = $login_error;
2869 function set_focus() {}
2870 if(document.getElementById("post_error")) {
2871 document.getElementById("post_error").innerHTML="'. $login_error. '";
2872 document.getElementById("cant_login").value=1;
2873 document.getElementById("login_button").disabled = true;
2874 document.getElementById("user_name").disabled = true;
2875 //document.getElementById("user_password").disabled = true;
2884 function sugar_cleanup($exit = false) {
2885 static $called = false;
2888 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2889 chdir(realpath(dirname(__FILE__) . '/..'));
2890 global $sugar_config;
2891 require_once('include/utils/LogicHook.php');
2892 LogicHook::initialize();
2893 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2895 //added this check to avoid errors during install.
2896 if (empty($sugar_config['dbconfig'])) {
2897 if ($exit) exit; else return;
2900 if (!class_exists('Tracker', true)) {
2901 require_once 'modules/Trackers/Tracker.php';
2904 // Now write the cached tracker_queries
2905 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2906 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2907 $GLOBALS['current_user']->savePreferencesToDB();
2910 //check to see if this is not an `ajax call AND the user preference error flag is set
2912 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2913 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2914 && ($_REQUEST['action']!='favorites' && $_REQUEST['action']!='DynamicAction')
2915 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2916 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2919 global $app_strings;
2920 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2921 $err_mess = $app_strings['ERROR_USER_PREFS'];
2922 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2925 ajaxStatus.flashStatus('$err_mess',7000);
2931 if(class_exists('DBManagerFactory')) {
2932 $db = DBManagerFactory::getInstance();
2940 register_shutdown_function('sugar_cleanup');
2944 check_logic_hook - checks to see if your custom logic is in the logic file
2945 if not, it will add it. If the file isn't built yet, it will create the file
2948 function check_logic_hook_file($module_name, $event, $action_array){
2949 require_once('include/utils/logic_utils.php');
2952 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2954 $hook_array = get_hook_array($module_name);
2956 if(check_existing_element($hook_array, $event, $action_array)==true){
2957 //the hook at hand is present, so do nothing
2962 if(!empty($hook_array[$event]))
2964 $logic_count = count($hook_array[$event]);
2967 if($action_array[0]==""){
2968 $action_array[0] = $logic_count + 1;
2970 $hook_array[$event][] = $action_array;
2973 //end if the file exists already
2976 if($action_array[0]==""){
2977 $action_array[0] = 1;
2979 $hook_array = array();
2980 $hook_array[$event][] = $action_array;
2981 //end if else file exists already
2983 if($add_logic == true){
2985 //reorder array by element[0]
2986 //$hook_array = reorder_array($hook_array, $event);
2987 //!!!Finish this above TODO
2989 $new_contents = replace_or_add_logic_type($hook_array);
2990 write_logic_file($module_name, $new_contents);
2992 //end if add_element is true
2995 //end function check_logic_hook_file
2998 function remove_logic_hook($module_name, $event, $action_array) {
2999 require_once('include/utils/logic_utils.php');
3002 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
3003 // The file exists, let's make sure the hook is there
3004 $hook_array = get_hook_array($module_name);
3006 if(check_existing_element($hook_array, $event, $action_array)==true){
3007 // The hook is there, time to take it out.
3009 foreach ( $hook_array[$event] as $i => $hook ) {
3010 // We don't do a full comparison below just in case the filename changes
3011 if ( $hook[0] == $action_array[0]
3012 && $hook[1] == $action_array[1]
3013 && $hook[3] == $action_array[3]
3014 && $hook[4] == $action_array[4] ) {
3015 unset($hook_array[$event][$i]);
3019 $new_contents = replace_or_add_logic_type($hook_array);
3020 write_logic_file($module_name, $new_contents);
3026 function display_stack_trace($textOnly=false){
3028 $stack = debug_backtrace();
3030 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
3038 foreach($stack as $item) {
3044 if(isset($item['file']))
3045 $file = $item['file'];
3046 if(isset($item['class']))
3047 $class = $item['class'];
3048 if(isset($item['line']))
3049 $line = $item['line'];
3050 if(isset($item['function']))
3051 $function = $item['function'];
3055 $out .= '<font color="black"><b>';
3061 $out .= '</b></font><font color="blue">';
3064 $out .= "[L:{$line}]";
3067 $out .= '</font><font color="red">';
3070 $out .= "({$class}:{$function})";
3073 $out .= '</font><br>';
3085 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
3086 $error_msg = " $errstr occurred in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
3087 $halt_script = true;
3089 case 2048: return; //depricated we have lots of these ignore them
3092 if ( error_reporting() & E_NOTICE ) {
3093 $halt_script = false;
3099 case E_USER_WARNING:
3100 case E_COMPILE_WARNING:
3101 case E_CORE_WARNING:
3104 $halt_script = false;
3109 case E_COMPILE_ERROR:
3113 $type = "Fatal Error";
3118 $type = "Parse Error";
3122 //don't know what it is might not be so bad
3123 $halt_script = false;
3124 $type = "Unknown Error ($errno)";
3127 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3129 display_stack_trace();
3139 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3141 set_error_handler('StackTraceErrorHandler');
3143 function get_sub_cookies($name){
3145 if(isset($_COOKIE[$name])){
3146 $subs = explode('#', $_COOKIE[$name]);
3147 foreach($subs as $cookie){
3148 if(!empty($cookie)){
3149 $cookie = explode('=', $cookie);
3151 $cookies[$cookie[0]] = $cookie[1];
3160 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3162 if(!empty($sub_object_array)){
3164 foreach($sub_object_array as $sub_object){
3166 //run_second level is set to true if you need to remove sub-sub components
3167 if($run_second_level==true){
3169 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3171 //end if run_second_level is true
3173 $sub_object->mark_deleted($sub_object->id);
3174 //end foreach sub component
3176 //end if this is not empty
3179 //end function mark_delete_components
3183 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3185 function return_bytes($val)
3188 $last = strtolower($val{strlen($val)-1});
3192 // The 'G' modifier is available since PHP 5.1.0
3205 * Adds the href HTML tags around any URL in the $string
3207 function url2html($string) {
3209 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3210 return $return_string;
3212 // End customization by Julian
3215 * tries to determine whether the Host machine is a Windows machine
3217 function is_windows() {
3218 static $is_windows = null;
3219 if (!isset($is_windows)) {
3220 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3226 * equivalent for windows filesystem for PHP's is_writable()
3227 * @param string file Full path to the file/dir
3228 * @return bool true if writable
3230 function is_writable_windows($file) {
3231 if($file{strlen($file)-1}=='/') {
3232 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3235 // the assumption here is that Windows has an inherited permissions scheme
3236 // any file that is a descendant of an unwritable directory will inherit
3237 // that property and will trigger a failure below.
3242 $file = str_replace("/", '\\', $file);
3244 if(file_exists($file)) {
3245 if (!($f = @sugar_fopen($file, 'r+')))
3251 if(!($f = @sugar_fopen($file, 'w')))
3260 * best guesses Timezone based on webserver's TZ settings
3262 function lookupTimezone($userOffset = 0)
3264 return TimeDate::guessTimezone($userOffset);
3267 function convert_module_to_singular($module_array){
3270 foreach($module_array as $key => $value){
3271 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3273 if($value=="Cases") {
3274 $module_array[$key] = "Case";
3276 if($key=="projecttask"){
3277 $module_array['ProjectTask'] = "Project Task";
3278 unset($module_array[$key]);
3282 return $module_array;
3284 //end function convert_module_to_singular
3288 * Given the bean_name which may be plural or singular return the singular
3289 * bean_name. This is important when you need to include files.
3291 function get_singular_bean_name($bean_name){
3292 global $beanFiles, $beanList;
3293 if(array_key_exists($bean_name, $beanList)){
3294 return $beanList[$bean_name];
3302 * Given the potential module name (singular name, renamed module name)
3303 * Return the real internal module name.
3305 function get_module_from_singular($singular) {
3307 // find the internal module name for a singular name
3308 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3310 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3312 foreach ($singular_modules as $mod_name=>$sin_name) {
3313 if ($singular == $sin_name and $mod_name != $sin_name) {
3319 // find the internal module name for a renamed module
3320 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3322 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3324 foreach ($moduleList as $mod_name=>$name) {
3325 if ($singular == $name and $mod_name != $name) {
3331 // if it's not a singular name, nor a renamed name, return the original value
3335 function get_label($label_tag, $temp_module_strings){
3336 global $app_strings;
3337 if(!empty($temp_module_strings[$label_tag])){
3339 $label_name = $temp_module_strings[$label_tag];
3341 if(!empty($app_strings[$label_tag])){
3342 $label_name = $app_strings[$label_tag];
3344 $label_name = $label_tag;
3349 //end function get_label
3353 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3355 $rel_list = array();
3357 foreach($focus->relationship_fields as $rel_key => $rel_value){
3358 if($rel_value == $relationship_name){
3359 $temp_bean = get_module_info($tar_rel_module);
3360 // echo $focus->$rel_key;
3361 $temp_bean->retrieve($focus->$rel_key);
3362 if($temp_bean->id!=""){
3364 $rel_list[] = $temp_bean;
3370 foreach($focus->field_defs as $field_name => $field_def){
3371 //Check if the relationship_name matches a "relate" field
3372 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3373 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3374 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3375 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3377 $temp_bean = get_module_info($tar_rel_module);
3378 // echo $focus->$field_def['id_name'];
3379 $temp_bean->retrieve($focus->$field_def['id_name']);
3380 if($temp_bean->id!=""){
3382 $rel_list[] = $temp_bean;
3385 //Check if the relationship_name matches a "link" in a relate field
3386 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3387 $temp_bean = get_module_info($tar_rel_module);
3388 // echo $focus->$rel_value['id_name'];
3389 $temp_bean->retrieve($focus->$rel_value['id_name']);
3390 if($temp_bean->id!=""){
3392 $rel_list[] = $temp_bean;
3398 // special case for unlisted parent-type relationships
3399 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3400 $temp_bean = get_module_info($tar_rel_module);
3401 $temp_bean->retrieve($focus->parent_id);
3402 if($temp_bean->id!=""){
3403 $rel_list[] = $temp_bean;
3410 //end function search_filter_rel_info
3413 function get_module_info($module_name){
3417 //Get dictionary and focus data for module
3418 $vardef_name = $beanList[$module_name];
3420 if($vardef_name=="aCase"){
3421 $class_name = "Case";
3423 $class_name = $vardef_name;
3426 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3430 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3432 $module_bean = new $vardef_name();
3433 return $module_bean;
3434 //end function get_module_table
3438 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3440 * @param string $moduleName
3442 function get_valid_bean_name($module_name){
3445 $vardef_name = $beanList[$module_name];
3446 if($vardef_name=="aCase"){
3447 $bean_name = "Case";
3449 $bean_name = $vardef_name;
3456 function checkAuthUserStatus(){
3463 * This function returns an array of phpinfo() results that can be parsed and
3464 * used to figure out what version we run, what modules are compiled in, etc.
3465 * @param $level int info level constant (1,2,4,8...64);
3466 * @return $returnInfo array array of info about the PHP environment
3467 * @author original by "code at adspeed dot com" Fron php.net
3468 * @author customized for Sugar by Chris N.
3470 function getPhpInfo($level=-1) {
3471 /** Name (constant) Value Description
3472 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3473 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3474 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3475 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3476 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3477 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3478 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3479 INFO_ALL -1 Shows all of the above. This is the default value.
3483 $phpinfo = ob_get_contents();
3486 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3487 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3488 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3489 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3492 $returnInfo = array();
3494 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3495 $returnInfo['PHP Version'] = $version[1];
3499 for ($i=1; $i<count($parsedInfo); $i++) {
3500 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3501 $vName = trim($match[1]);
3502 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3504 foreach ($parsedInfo2 AS $vOne) {
3505 $vPat = '<info>([^<]+)<\/info>';
3506 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3507 $vPat2 = "/$vPat\s*$vPat/";
3509 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3510 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3511 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3512 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3524 * This function will take a string that has tokens like {0}, {1} and will replace
3525 * those tokens with the args provided
3526 * @param $format string to format
3527 * @param $args args to replace
3528 * @return $result a formatted string
3530 function string_format($format, $args){
3534 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3535 * IN () fails and IN ('') works.
3537 if (count($args) == 1)
3540 $singleArgument = current($args);
3541 if (empty($singleArgument))
3543 return str_replace("{0}", "''", $result);
3548 for($i = 0; $i < count($args); $i++){
3549 $result = str_replace('{'.$i.'}', $args[$i], $result);
3555 * Generate a string for displaying a unique identifier that is composed
3556 * of a system_id and number. This is use to allow us to generate quote
3557 * numbers using a DB auto-increment key from offline clients and still
3558 * have the number be unique (since it is modified by the system_id.
3560 * @param $num of bean
3561 * @param $system_id from system
3562 * @return $result a formatted string
3564 function format_number_display($num, $system_id){
3565 global $sugar_config;
3566 if(isset($num) && !empty($num)){
3567 $num=unformat_number($num);
3568 if(isset($system_id) && $system_id == 1){
3569 return sprintf("%d", $num);
3572 return sprintf("%d-%d", $num, $system_id);
3576 function checkLoginUserStatus(){
3580 * This function will take a number and system_id and format
3581 * @param $url URL containing host to append port
3582 * @param $port the port number - if '' is passed, no change to url
3583 * @return $resulturl the new URL with the port appended to the host
3585 function appendPortToHost($url, $port)
3589 // if no port, don't change the url
3592 $split = explode("/", $url);
3593 //check if it starts with http, in case they didn't include that in url
3594 if(str_begin($url, 'http'))
3596 //third index ($split[2]) will be the host
3597 $split[2] .= ":".$port;
3599 else // otherwise assumed to start with host name
3601 //first index ($split[0]) will be the host
3602 $split[0] .= ":".$port;
3605 $resulturl = implode("/", $split);
3612 * Singleton to return JSON object
3613 * @return JSON object
3615 function getJSONobj() {
3616 static $json = null;
3618 require_once('include/JSON.php');
3619 $json = new JSON(JSON_LOOSE_TYPE);
3624 require_once('include/utils/db_utils.php');
3627 * Set default php.ini settings for entry points
3629 function setPhpIniSettings() {
3631 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3633 if(function_exists('gzclose') && headers_sent() == false) {
3634 ini_set('zlib.output_compression', 1);
3638 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3640 /*if(function_exists('mb_strlen')) {
3641 ini_set('mbstring.func_overload', 7);
3642 ini_set('mbstring.internal_encoding', 'UTF-8');
3646 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3647 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3648 $backtrack_limit = ini_get('pcre.backtrack_limit');
3649 if(!empty($backtrack_limit)) {
3650 ini_set('pcre.backtrack_limit', '-1');
3655 * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
3656 * language files. Language file merges do not need to account for null values so we can get some
3657 * performance increases by using this specialized function. Note this merge function does not properly
3658 * handle null values.
3664 function sugarLangArrayMerge($gimp, $dom)
3666 if(is_array($gimp) && is_array($dom))
3668 foreach($dom as $domKey => $domVal)
3670 if(isset($gimp[$domKey]))
3672 if(is_array($domVal))
3675 foreach ( $domVal as $domArrKey => $domArrVal )
3676 $tempArr[$domArrKey] = $domArrVal;
3677 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3678 if ( !isset($tempArr[$gimpArrKey]) )
3679 $tempArr[$gimpArrKey] = $gimpArrVal;
3680 $gimp[$domKey] = $tempArr;
3684 $gimp[$domKey] = $domVal;
3689 $gimp[$domKey] = $domVal;
3693 // if the passed value for gimp isn't an array, then return the $dom
3694 elseif(is_array($dom))
3702 * like array_merge() but will handle array elements that are themselves arrays;
3703 * PHP's version just overwrites the element with the new one.
3705 * @internal Note that this function deviates from the internal array_merge()
3706 * functions in that it does does not treat numeric keys differently
3707 * than string keys. Additionally, it deviates from
3708 * array_merge_recursive() by not creating an array when like values
3711 * @param array gimp the array whose values will be overloaded
3712 * @param array dom the array whose values will pwn the gimp's
3713 * @return array beaten gimp
3715 function sugarArrayMerge($gimp, $dom) {
3716 if(is_array($gimp) && is_array($dom)) {
3717 foreach($dom as $domKey => $domVal) {
3718 if(array_key_exists($domKey, $gimp)) {
3719 if(is_array($domVal)) {
3721 foreach ( $domVal as $domArrKey => $domArrVal )
3722 $tempArr[$domArrKey] = $domArrVal;
3723 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3724 if ( !array_key_exists($gimpArrKey, $tempArr) )
3725 $tempArr[$gimpArrKey] = $gimpArrVal;
3726 $gimp[$domKey] = $tempArr;
3728 $gimp[$domKey] = $domVal;
3731 $gimp[$domKey] = $domVal;
3735 // if the passed value for gimp isn't an array, then return the $dom
3736 elseif(is_array($dom))
3743 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3745 * @param array gimp the array whose values will be overloaded
3746 * @param array dom the array whose values will pwn the gimp's
3747 * @return array beaten gimp
3749 function sugarArrayMergeRecursive($gimp, $dom) {
3750 if(is_array($gimp) && is_array($dom)) {
3751 foreach($dom as $domKey => $domVal) {
3752 if(array_key_exists($domKey, $gimp)) {
3753 if(is_array($domVal) && is_array($gimp[$domKey])) {
3754 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3756 $gimp[$domKey] = $domVal;
3759 $gimp[$domKey] = $domVal;
3763 // if the passed value for gimp isn't an array, then return the $dom
3764 elseif(is_array($dom))
3771 * finds the correctly working versions of PHP-JSON
3772 * @return bool True if NOT found or WRONG version
3774 function returnPhpJsonStatus() {
3775 if(function_exists('json_encode')) {
3776 $phpInfo = getPhpInfo(8);
3777 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3779 return true; // not found
3784 * getTrackerSubstring
3786 * Returns a [number]-char or less string for the Tracker to display in the header
3787 * based on the tracker_max_display_length setting in config.php. If not set,
3788 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3790 * @param string name field for a given Object
3791 * @return string [number]-char formatted string if length of string exceeds the max allowed
3793 function getTrackerSubstring($name) {
3794 static $max_tracker_item_length;
3797 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3798 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3800 global $sugar_config;
3802 if(!isset($max_tracker_item_length)) {
3803 if(isset($sugar_config['tracker_max_display_length'])) {
3804 $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;
3806 $max_tracker_item_length = 15;
3810 if($strlen > $max_tracker_item_length) {
3811 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length-3, "UTF-8") : substr($name, 0, $max_tracker_item_length-3);
3819 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3820 $where_clauses= array();
3822 $table_name=$bean->object_name;
3823 foreach ($field_list[$module] as $field=>$parms) {
3824 if(isset($values[$field]) && $values[$field] != "") {
3826 if (!empty($parms['operator'])) {
3827 $operator=$parms['operator'];
3829 if (is_array($values[$field])) {
3832 foreach ($values[$field] as $key => $val) {
3833 if ($val != ' ' and $val != '') {
3834 if (!empty($field_value)) {
3837 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3841 $field_value=$GLOBALS['db']->quote($values[$field]);
3843 //set db_fields array.
3844 if (!isset($parms['db_field']) ) {
3845 $parms['db_field'] = array($field);
3847 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3848 global $current_user;
3849 $field_value = $GLOBALS['db']->quote($current_user->id);
3855 if ($field_value != '') {
3857 foreach ($parms['db_field'] as $db_field) {
3858 if (strstr($db_field,'.')===false) {
3859 $db_field=$bean->table_name.".".$db_field;
3861 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3862 $db_field='upper('.$db_field.")";
3863 $field_value=strtoupper($field_value);
3867 if (!empty($where)) {
3870 switch (strtolower($operator)) {
3872 $where .= $db_field . " like '".$field_value.$like_char."'";
3875 $where .= $db_field . " in (".$field_value.')';
3878 $where .= $db_field . " = '".$field_value ."'";
3883 if (!empty($where)) {
3885 array_push($where_clauses, '( '.$where.' )');
3887 array_push($where_clauses, $where);
3892 if ($add_custom_fields) {
3893 require_once('modules/DynamicFields/DynamicField.php');
3894 $bean->setupCustomFields($module);
3895 $bean->custom_fields->setWhereClauses($where_clauses);
3897 return $where_clauses;
3900 function add_quotes($str) {
3905 * This function will rebuild the config file
3906 * @param $sugar_config
3907 * @param $sugar_version
3908 * @return bool true if successful
3910 function rebuildConfigFile($sugar_config, $sugar_version) {
3911 // add defaults to missing values of in-memory sugar_config
3912 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3913 // need to override version with default no matter what
3914 $sugar_config['sugar_version'] = $sugar_version;
3916 ksort( $sugar_config );
3918 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3927 * Loads clean configuration, not overridden by config_override.php
3931 function loadCleanConfig()
3933 $sugar_config = array();
3934 require 'config.php';
3935 return $sugar_config;
3939 * getJavascriptSiteURL
3940 * This function returns a URL for the client javascript calls to access
3941 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3942 * are used to access the site. Thus, the hostname in the URL returned may
3943 * not always match that of $sugar_config['site_url']. Basically, the
3944 * assumption is that however the user accessed the website is how they
3945 * will continue to with subsequent javascript requests. If the variable
3946 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3947 * @return $site_url The url used to refer to the website
3949 function getJavascriptSiteURL() {
3950 global $sugar_config;
3951 if(!empty($_SERVER['HTTP_REFERER'])) {
3952 $url = parse_url($_SERVER['HTTP_REFERER']);
3953 $replacement_url = $url['scheme']."://".$url['host'];
3954 if(!empty($url['port']))
3955 $replacement_url .= ':'.$url['port'];
3956 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3958 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3959 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3960 $site_url = preg_replace('/^http\:/','https:',$site_url);
3963 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3967 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3968 function add_squotes($str) {
3969 return "'" . $str . "'";
3973 // recursive function to count the number of levels within an array
3974 function array_depth($array, $depth_count=-1, $depth_array=array()){
3976 if (is_array($array)){
3977 foreach ($array as $key => $value){
3978 $depth_array[] = array_depth($value, $depth_count);
3982 return $depth_count;
3984 foreach ($depth_array as $value){
3985 $depth_count = $value > $depth_count ? $value : $depth_count;
3987 return $depth_count;
3991 * Creates a new Group User
3992 * @param string $name Name of Group User
3993 * @return string GUID of new Group User
3995 function createGroupUser($name) {
3998 $group = new User();
3999 $group->user_name = $name;
4000 $group->last_name = $name;
4001 $group->is_group = 1;
4002 $group->deleted = 0;
4003 $group->status = 'Active'; // cn: bug 6711
4004 $group->setPreference('timezone', TimeDate::userTimezone());
4011 * Helper function to locate an icon file given only a name
4012 * Searches through the various paths for the file
4013 * @param string iconFileName The filename of the icon
4014 * @return string Relative pathname of the located icon, or '' if not found
4017 function _getIcon($iconFileName)
4020 $iconName = "icon_{$iconFileName}.gif";
4021 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
4023 //First try un-ucfirst-ing the icon name
4024 if ( empty($iconFound) )
4025 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
4026 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
4028 //Next try removing the icon prefix
4029 if ( empty($iconFound) )
4030 $iconName = "{$iconFileName}.gif";
4031 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
4033 if ( empty($iconFound) )
4039 * Function to grab the correct icon image for Studio
4040 * @param string $iconFileName Name of the icon file
4041 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
4042 * @param string $width Width of image
4043 * @param string $height Height of image
4044 * @param string $align Alignment of image
4045 * @param string $alt Alt tag of image
4046 * @return string $string <img> tag with corresponding image
4049 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
4051 global $app_strings, $theme;
4053 $iconName = _getIcon($iconFileName);
4054 if(empty($iconName)){
4055 $iconName = _getIcon($altFileName);
4056 if (empty($iconName))
4058 return $app_strings['LBL_NO_IMAGE'];
4061 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4065 * Function to grab the correct icon image for Dashlets Dialog
4066 * @param string $filename Location of the icon file
4067 * @param string $module Name of the module to fall back onto if file does not exist
4068 * @param string $width Width of image
4069 * @param string $height Height of image
4070 * @param string $align Alignment of image
4071 * @param string $alt Alt tag of image
4072 * @return string $string <img> tag with corresponding image
4075 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
4076 global $app_strings, $theme;
4077 $iconName = _getIcon($module . "_32");
4078 if (empty($iconName))
4080 $iconName = _getIcon($module);
4082 if(empty($iconName)){
4083 return $app_strings['LBL_NO_IMAGE'];
4085 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4088 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
4089 function html_entity_decode_utf8($string)
4092 // replace numeric entities
4093 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
4094 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
4095 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
4096 // replace literal entities
4097 if (!isset($trans_tbl))
4099 $trans_tbl = array();
4100 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
4101 $trans_tbl[$key] = utf8_encode($val);
4103 return strtr($string, $trans_tbl);
4106 // Returns the utf string corresponding to the unicode value
4107 function code2utf($num)
4109 if ($num < 128) return chr($num);
4110 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
4111 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4112 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4116 function str_split_php4($string, $length = 1) {
4117 $string_length = strlen($string);
4120 if ($length > $string_length) {
4121 // use the string_length as the string is shorter than the length
4122 $length = $string_length;
4124 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
4125 $return[] = substr($string, $cursor, $length);
4130 if (version_compare(phpversion(), '5.0.0', '<')) {
4131 function str_split($string, $length = 1) {
4132 return str_split_php4($string, $length);
4137 * @deprecated use DBManagerFactory::isFreeTDS
4139 function is_freetds()
4141 return DBManagerFactory::isFreeTDS();
4145 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
4147 * @todo this won't work completely right until we impliment css compression and combination
4148 * for now, we'll just include the last css file found.
4150 * @return chart.css file to use
4152 function chartStyle()
4154 return SugarThemeRegistry::current()->getCSSURL('chart.css');
4158 * Chart dashlet helper functions that returns the correct XML color file for charts,
4159 * dependent on the current theme.
4161 * @return sugarColors.xml to use
4163 function chartColors()
4165 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
4166 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4167 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4169 /* End Chart Dashlet helper functions */
4172 * This function is designed to set up the php enviroment
4173 * for AJAX requests.
4176 function ajaxInit() {
4177 ini_set('display_errors', 'false');
4181 * Returns an absolute path from the given path, determining if it is relative or absolute
4183 * @param string $path
4186 function getAbsolutePath(
4188 $currentServer = false
4191 $path = trim($path);
4193 // try to match absolute paths like \\server\share, /directory or c:\
4194 if ( ( substr($path,0,2) == '\\\\' )
4195 || ( $path[0] == '/' )
4196 || preg_match('/^[A-z]:/i',$path)
4200 return getcwd().'/'.$path;
4204 * Returns the bean object of the given module
4206 * @deprecated use SugarModule::loadBean() instead
4207 * @param string $module
4214 return SugarModule::get($module)->loadBean();
4219 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4221 function isTouchScreen()
4223 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4225 // first check if we have forced use of the touch enhanced interface
4226 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4230 // next check if we should use the touch interface with our device
4231 if ( strpos($ua, 'ipad') !== false ) {
4239 * Returns the shortcut keys to access the shortcut links. Shortcut
4240 * keys vary depending on browser versions and operating systems.
4241 * @return String value of the shortcut keys
4243 function get_alt_hot_key() {
4245 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4246 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4247 $isMac = strpos($ua, 'mac') !== false;
4248 $isLinux = strpos($ua, 'linux') !== false;
4250 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4251 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4252 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4255 return $isMac ? 'Ctrl+' : 'Alt+';
4258 function can_start_session(){
4259 if(!empty($_GET['PHPSESSID'])) {
4262 $session_id = session_id();
4263 return empty($session_id) ? true : false;
4266 function load_link_class($properties){
4268 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4269 require_once($properties['link_file']);
4270 $class = $properties['link_class'];
4276 function inDeveloperMode()
4278 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4282 * Filter the protocol list for inbound email accounts.
4284 * @param array $protocol
4286 function filterInboundEmailPopSelection($protocol)
4288 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4290 if( isset($protocol['pop3']) )
4291 unset($protocol['pop3']);
4294 $protocol['pop3'] = 'POP3';
4300 * The function is used because currently we are not supporting mbstring.func_overload
4301 * 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.
4302 * 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.
4303 * @returns the substred strings.
4305 function sugar_substr($string, $length, $charset='UTF-8')
4307 if(mb_strlen($string,$charset) > $length) {
4308 $string = trim(mb_substr(trim($string),0,$length,$charset));
4314 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4315 * This will work even without setting the mbstring.*encoding
4317 function sugar_ucfirst($string, $charset='UTF-8') {
4318 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4325 function unencodeMultienum($string) {
4326 if (is_array($string))
4330 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4331 $string = substr(substr($string, 1), 0, strlen($string) -2);
4334 return explode('^,^', $string);
4337 function encodeMultienumValue($arr) {
4338 if (!is_array($arr))
4344 $string = "^" . implode('^,^', $arr) . "^";
4350 * create_export_query is used for export and massupdate
4351 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4352 * This function will correct the where clause and output necessary join condition for them
4353 * @param $module: the module name
4354 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4355 * @param $where: where clauses
4356 * @return $ret_array['where']: corrected where clause
4357 * @return $ret_array['join']: extra join condition
4359 function create_export_query_relate_link_patch($module, $searchFields, $where){
4360 if(file_exists('modules/'.$module.'/SearchForm.html')){
4361 $ret_array['where'] = $where;
4364 $seed = loadBean($module);
4365 foreach($seed->field_defs as $name=>$field)
4368 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4369 $seed->load_relationship($field['link']);
4371 if(empty($join_type))
4373 $params['join_type'] = ' LEFT JOIN ';
4377 $params['join_type'] = $join_type;
4379 if(isset($data['join_name']))
4381 $params['join_table_alias'] = $field['join_name'];
4385 $params['join_table_alias'] = 'join_'.$field['name'];
4388 if(isset($data['join_link_name']))
4390 $params['join_table_link_alias'] = $field['join_link_name'];
4394 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4396 $join = $seed->$field['link']->getJoin($params, true);
4397 $join_table_alias = 'join_'.$field['name'];
4398 if(isset($field['db_concat_fields'])){
4399 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4400 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4402 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4406 $ret_array = array('where'=>$where, 'join'=> isset($join['join']) ? $join['join'] : '');
4411 * 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.
4412 * @Depends on QuickRepairAndRebuild.php
4413 * @Relate bug 30642 ,23177
4415 function clearAllJsAndJsLangFilesWithoutOutput(){
4416 global $current_language , $mod_strings;
4417 $MBmodStrings = $mod_strings;
4418 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4419 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4420 $repair = new RepairAndClear();
4421 $repair->module_list = array();
4422 $repair->show_output = false;
4423 $repair->clearJsLangFiles();
4424 $repair->clearJsFiles();
4425 $mod_strings = $MBmodStrings;
4429 * This function will allow you to get a variable value from query string
4431 function getVariableFromQueryString($variable, $string){
4433 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4443 * should_hide_iframes
4444 * This is a helper method to determine whether or not to show iframes (My Sites) related
4445 * information in the application.
4447 * @return boolean flag indicating whether or not iframes module should be hidden
4449 function should_hide_iframes() {
4450 //Remove the MySites module
4451 if(file_exists('modules/iFrames/iFrame.php')) {
4452 if(!class_exists("iFrame")) {
4453 require_once('modules/iFrames/iFrame.php');
4461 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4463 * @param string $version
4464 * @return string RC, BETA, GA
4466 function getVersionStatus($version){
4467 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4468 return strtoupper($matches[1]);
4475 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4476 * 5.5.1RC1 then return 5.5.1
4478 * @param string $version
4481 function getMajorMinorVersion($version){
4482 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4483 $version = $matches2[1];
4484 $arr = explode('.', $version);
4485 if(count($arr) > 2){
4487 $version = substr($version, 0, 3);
4495 * Return string composed of seconds & microseconds of current time, without dots
4498 function sugar_microtime()
4500 $now = explode(' ', microtime());
4501 $unique_id = $now[1].str_replace('.', '', $now[0]);
4506 * Extract urls from a piece of text
4508 * @return array of urls found in $string
4510 function getUrls($string)
4512 $lines = explode("<br>", trim($string));
4514 foreach($lines as $line){
4515 $regex = '/http?\:\/\/[^\" ]+/i';
4516 preg_match_all($regex, $line, $matches);
4517 foreach($matches[0] as $match){
4526 * Sanitize image file from hostile content
4527 * @param string $path Image file
4528 * @param bool $jpeg Accept only JPEGs?
4530 function verify_image_file($path, $jpeg = false)
4532 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4533 $img = imagecreatefromstring(file_get_contents($path));
4537 $img_size = getimagesize($path);
4538 $filetype = $img_size['mime'];
4539 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4540 if($filetype == "image/jpeg" || $jpeg) {
4543 $image = ob_get_clean();
4544 // not writing directly because imagejpeg does not work with streams
4545 if(file_put_contents($path, $image)) {
4548 } elseif ($filetype == "image/png") {
4549 // else if the filetype is png, create png
4550 imagealphablending($img, true);
4551 imagesavealpha($img, true);
4554 $image = ob_get_clean();
4555 if(file_put_contents($path, $image)) {
4562 // check image manually
4563 $fp = fopen($path, "rb");
4564 if(!$fp) return false;
4566 // read the whole file in chunks
4568 $data .= fread($fp,8192);
4572 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",
4574 $GLOBALS['log']->fatal("Found {$m[0]} in $path, not allowing upload");
4583 * Verify uploaded image
4584 * Verifies that image has proper extension, MIME type and doesn't contain hostile content
4585 * @param string $path Image path
4586 * @param bool $jpeg_only Accept only JPEGs?
4588 function verify_uploaded_image($path, $jpeg_only = false)
4590 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4592 $supportedExtensions['png'] = 'image/png';
4595 if(!file_exists($path) || !is_file($path)) {
4599 $img_size = getimagesize($path);
4600 $filetype = $img_size['mime'];
4601 $ext = end(explode(".", $path));
4602 if(substr_count('..', $path) > 0 || ($ext !== $path && !isset($supportedExtensions[strtolower($ext)])) ||
4603 !in_array($filetype, array_values($supportedExtensions))) {
4606 return verify_image_file($path, $jpeg_only);
4609 function cmp_beans($a, $b)
4611 global $sugar_web_service_order_by;
4612 //If the order_by field is not valid, return 0;
4613 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4616 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4617 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4621 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4629 function order_beans($beans, $field_name)
4631 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4632 global $sugar_web_service_order_by;
4633 $sugar_web_service_order_by = $field_name;
4634 usort($beans, "cmp_beans");
4639 * Return search like string
4640 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4641 * @param string $str string to be searched
4642 * @param string $like_char Database like character, usually '%'
4643 * @return string Returns a string to be searched in db query
4645 function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true) {
4647 // override default wildcard character
4648 if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4649 strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4650 $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4653 // add wildcard at the beginning of the search string
4654 if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4655 $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4656 if (substr($str,0,1) <> $wildcard)
4657 $str = $wildcard.$str;
4660 // add wildcard at the end of search string (default)
4661 if ($appendWildcard) {
4662 if(substr($str,-1) <> $wildcard) {
4667 return str_replace($wildcard, $like_char, $str);
4670 //check to see if custom utils exists
4671 if(file_exists('custom/include/custom_utils.php')){
4672 include_once('custom/include/custom_utils.php');
4675 //check to see if custom utils exists in Extension framework
4676 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4677 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4680 * @param $input - the input string to sanitize
4681 * @param int $quotes - use quotes
4682 * @param string $charset - the default charset
4683 * @param bool $remove - strip tags or not
4684 * @return string - the sanitized string
4686 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4688 return htmlentities($input, $quotes, $charset);
4692 * @return string - the full text search engine name
4694 function getFTSEngineType()
4696 if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
4697 foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
4705 * @param string $optionName - name of the option to be retrieved from app_list_strings
4706 * @return array - the array to be used in option element
4708 function getFTSBoostOptions($optionName)
4710 if (isset($GLOBALS['app_list_strings'][$optionName])) {
4711 return $GLOBALS['app_list_strings'][$optionName];
4719 * utf8_recursive_encode
4721 * This function walks through an Array and recursively calls utf8_encode on the
4722 * values of each of the elements.
4724 * @param $data Array of data to encode
4725 * @return utf8 encoded Array data
4727 function utf8_recursive_encode($data)
4730 foreach($data as $key=>$val) {
4731 if(is_array($val)) {
4732 $result[$key] = utf8_recursive_encode($val);
4734 $result[$key] = utf8_encode($val);
4741 * get_language_header
4743 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4744 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4746 * @return String The lang=[Current Language] markup to insert into the <html> tag
4748 function get_language_header()
4750 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4755 * get_custom_file_if_exists
4757 * This function handles the repetitive code we have where we first check if a file exists in the
4758 * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
4759 * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
4760 * otherwise it return $file
4762 * @param $file String of filename to check
4763 * @return $file String of filename including custom directory if found
4765 function get_custom_file_if_exists($file)
4767 return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4774 * This will return the URL used to redirect the user to the help documentation.
4775 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4776 * in config.php or config_override.php.
4778 * @param string $send_edition
4779 * @param string $send_version
4780 * @param string $send_lang
4781 * @param string $send_module
4782 * @param string $send_action
4783 * @param string $dev_status
4784 * @param string $send_key
4785 * @param string $send_anchor
4786 * @return string the completed help URL
4788 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4789 global $sugar_config;
4791 if (!empty($sugar_config['custom_help_url'])) {
4792 $sendUrl = $sugar_config['custom_help_url'];
4794 if (!empty($sugar_config['custom_help_base_url'])) {
4795 $baseUrl= $sugar_config['custom_help_base_url'];
4797 $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4799 $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4800 if(!empty($send_anchor)) {
4801 $sendUrl .= "&anchor=".$send_anchor;
4808 * generateETagHeader
4810 * This function generates the necessary cache headers for using ETags with dynamic content. You
4811 * simply have to generate the ETag, pass it in, and the function handles the rest.
4813 * @param string $etag ETag to use for this content.
4815 function generateETagHeader($etag){
4816 header("cache-control:");
4817 header('Expires: ');
4818 header("ETag: " . $etag);
4820 if(isset($_SERVER["HTTP_IF_NONE_MATCH"])){
4821 if($etag == $_SERVER["HTTP_IF_NONE_MATCH"]){
4823 header("Status: 304 Not Modified");
4824 header("HTTP/1.0 304 Not Modified");
4831 * getReportNameTranslation
4833 * Translates the report name if a translation exists,
4834 * otherwise just returns the name
4836 * @param string $reportName
4837 * @return string translated report name
4839 function getReportNameTranslation($reportName) {
4840 global $current_language;
4842 // Used for translating reports
4843 $mod_strings = return_module_language($current_language, 'Reports');
4845 // Search for the report name in the default language and get the key
4846 $key = array_search($reportName, return_module_language("", "Reports"));
4848 // If the key was found, use it to get a translation, otherwise just use report name
4850 $title = $mod_strings[$key];
4852 $title = $reportName;
4859 * Remove vars marked senstitive from array
4860 * @param array $defs
4861 * @param SugarBean|array $data
4862 * @return mixed $data without sensitive fields
4864 function clean_sensitive_data($defs, $data)
4866 foreach($defs as $field => $def) {
4867 if(!empty($def['sensitive'])) {
4868 if(is_array($data)) {
4871 if($data instanceof SugarBean) {
4880 * Return relations with labels for duplicates
4882 function getDuplicateRelationListWithTitle($def, $var_def, $module)
4884 global $current_language;
4885 $select_array = array_unique($def);
4886 if (count($select_array) < count($def))
4888 $temp_module_strings = return_module_language($current_language, $module);
4889 $temp_duplicate_array = array_diff_assoc($def, $select_array);
4890 $temp_duplicate_array = array_merge($temp_duplicate_array, array_intersect($select_array, $temp_duplicate_array));
4892 foreach ($temp_duplicate_array as $temp_key => $temp_value)
4894 // Don't add duplicate relationships
4895 if (!empty($var_def[$temp_key]['relationship']) && array_key_exists($var_def[$temp_key]['relationship'], $select_array))
4899 $select_array[$temp_key] = $temp_value;
4902 // Add the relationship name for easier recognition
4903 foreach ($select_array as $key => $value)
4905 $select_array[$key] .= ' (' . $key . ')';
4908 asort($select_array);
4909 return $select_array;
4913 * Gets the list of "*type_display*".
4917 function getTypeDisplayList()
4919 return array('record_type_display', 'parent_type_display', 'record_type_display_notes');
4923 * Breaks given string into substring according
4924 * to 'db_concat_fields' from field definition
4925 * and assigns values to corresponding properties
4928 * @param SugarBean $bean
4929 * @param array $fieldDef
4930 * @param string $value
4932 function assignConcatenatedValue(SugarBean $bean, $fieldDef, $value)
4934 $valueParts = explode(' ',$value);
4935 $valueParts = array_filter($valueParts);
4936 $fieldNum = count($fieldDef['db_concat_fields']);
4938 if (count($valueParts) == 1 && $fieldDef['db_concat_fields'] == array('first_name', 'last_name'))
4940 $bean->last_name = $value;
4942 // elseif ($fieldNum >= count($valueParts))
4945 for ($i = 0; $i < $fieldNum; $i++)
4947 $fieldValue = array_shift($valueParts);
4948 $fieldName = $fieldDef['db_concat_fields'][$i];
4949 $bean->$fieldName = $fieldValue !== false ? $fieldValue : '';
4952 if (!empty($valueParts))
4954 $bean->$fieldName .= ' ' . implode(' ', $valueParts);