2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
37 /*********************************************************************************
39 * Description: Includes generic helper functions used throughout the application.
40 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41 * All Rights Reserved.
42 * Contributor(s): ______________________________________..
43 ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/security_utils.php');
49 function make_sugar_config(&$sugar_config)
51 /* used to convert non-array config.php file to array format */
52 global $admin_export_only;
54 global $calculate_response_time;
55 global $create_default_user;
58 global $dbconfigoption;
59 global $default_action;
60 global $default_charset;
61 global $default_currency_name;
62 global $default_currency_symbol;
63 global $default_currency_iso4217;
64 global $defaultDateFormat;
65 global $default_language;
66 global $default_module;
67 global $default_password;
68 global $default_permission_mode;
69 global $default_theme;
70 global $defaultTimeFormat;
71 global $default_user_is_admin;
72 global $default_user_name;
73 global $disable_export;
74 global $disable_persistent_connections;
75 global $display_email_template_variable_chooser;
76 global $display_inbound_email_buttons;
77 global $history_max_viewed;
81 global $list_max_entries_per_page;
82 global $lock_default_user_name;
83 global $log_memory_usage;
85 global $requireAccounts;
86 global $RSS_CACHE_TIME;
90 global $sugar_version;
93 global $translation_string_prefix;
95 global $upload_badext;
97 global $upload_maxsize;
98 global $import_max_execution_time;
99 global $list_max_entries_per_subpanel;
100 global $passwordsetting;
102 // assumes the following variables must be set:
103 // $dbconfig, $dbconfigoption, $cache_dir, $session_dir, $site_URL, $upload_dir
105 $sugar_config = array (
106 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
107 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
108 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
109 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
110 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
111 'chartEngine' => 'Jit',
112 'date_formats' => empty($dateFormats) ? array(
113 'Y-m-d'=>'2010-12-23',
114 'd-m-Y' => '23-12-2010',
115 'm-d-Y'=>'12-23-2010',
116 'Y/m/d'=>'2010/12/23',
117 'd/m/Y' => '23/12/2010',
118 'm/d/Y'=>'12/23/2010',
119 'Y.m.d' => '2010.12.23',
120 'd.m.Y' => '23.12.2010',
121 'm.d.Y' => '12.23.2010'
123 'dbconfig' => $dbconfig, // this must be set!!
124 'dbconfigoption' => $dbconfigoption, // this must be set!!
125 'default_action' => empty($default_action) ? 'index' : $default_action,
126 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
127 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
128 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
129 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
130 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
131 'default_locale_name_format' => empty($defaultNameFormat) ? 's f l' : $defaultNameFormat,
132 'default_export_charset' => 'UTF-8',
133 'default_language' => empty($default_language) ? 'en_us' : $default_language,
134 'default_module' => empty($default_module) ? 'Home' : $default_module,
135 'default_password' => empty($default_password) ? '' : $default_password,
136 'default_permissions' => array (
142 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
143 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
144 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
145 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
146 'disable_export' => empty($disable_export) ? false : $disable_export,
147 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
148 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
149 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
150 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
151 'host_name' => empty($host_name) ? 'localhost' : $host_name,
152 'import_dir' => $import_dir, // this must be set!!
153 'import_max_records_per_file' => 100,
154 'import_max_records_total_limit' => '',
155 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
156 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
157 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
158 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
159 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
160 'name_formats' => empty($nameFormats) ? array(
161 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
162 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
164 'portal_view' => 'single_user',
165 'resource_management' => array (
166 'special_query_limit' => 50000,
167 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
168 'default_limit' => 1000,
170 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
171 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
172 'session_dir' => $session_dir, // this must be set!!
173 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
174 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
175 'showThemePicker' => true,
176 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
177 'time_formats' => empty($timeFormats) ? array (
178 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
179 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
180 'tmp_dir' => $tmp_dir, // this must be set!!
181 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
182 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
183 'upload_badext' => empty($upload_badext) ? array (
184 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
185 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
186 'upload_dir' => $upload_dir, // this must be set!!
187 'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
188 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
189 'lock_homepage' => false,
190 'lock_subpanels' => false,
191 'max_dashlets_homepage' => 15,
192 'dashlet_display_row_options' => array('1','3','5','10'),
193 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
194 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
195 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
196 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
197 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
198 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
199 'default_call_status' => 'Planned',
200 'js_lang_version' => 1,
201 'passwordsetting' => empty($passwordsetting) ? array (
202 'SystemGeneratedPasswordON' => '',
203 'generatepasswordtmpl' => '',
204 'lostpasswordtmpl' => '',
205 'forgotpasswordON' => true,
206 'linkexpiration' => '1',
207 'linkexpirationtime' => '30',
208 'linkexpirationtype' => '1',
209 'systexpiration' => '0',
210 'systexpirationtime' => '',
211 'systexpirationtype' => '0',
212 'systexpirationlogin' => '',
213 ) : $passwordsetting,
214 'use_sprites' => function_exists('imagecreatetruecolor'),
215 'search_wildcard_infront' => false,
216 'search_wildcard_char' => '%',
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
223 'max_cron_jobs' => 10, // max jobs per cron schedule run
224 'max_cron_runtime' => 60, // max runtime for cron jobs
225 'min_cron_interval' => 30, // minimal interval between cron jobs
230 function get_sugar_config_defaults() {
233 * used for getting base values for array style config.php. used by the
234 * installer and to fill in new entries on upgrades. see also:
238 $sugar_config_defaults = array (
239 'admin_export_only' => false,
240 'export_delimiter' => ',',
241 'cache_dir' => 'cache/',
242 'calculate_response_time' => true,
243 'create_default_user' => false,
244 'chartEngine' => 'Jit',
245 'date_formats' => array (
246 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
247 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
248 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
249 'name_formats' => array (
250 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
251 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
253 'dbconfigoption' => array (
254 'persistent' => true,
258 'default_action' => 'index',
259 'default_charset' => return_session_value_or_default('default_charset',
261 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
262 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
263 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
264 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
265 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
266 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
267 'default_date_format' => 'm/d/Y',
268 'default_locale_name_format' => 's f l',
269 'default_export_charset' => 'UTF-8',
270 'default_language' => return_session_value_or_default('default_language',
272 'default_module' => 'Home',
273 'default_password' => '',
274 'default_permissions' => array (
280 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
281 'default_time_format' => 'h:ia',
282 'default_user_is_admin' => false,
283 'default_user_name' => '',
284 'disable_export' => false,
285 'disable_persistent_connections' =>
286 return_session_value_or_default('disable_persistent_connections',
288 'display_email_template_variable_chooser' => false,
289 'display_inbound_email_buttons' => false,
290 'dump_slow_queries' => false,
291 'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
292 'email_default_editor' => 'html',
293 'email_default_client' => 'sugar',
294 'email_default_delete_attachments' => true,
295 'history_max_viewed' => 50,
296 'installer_locked' => true,
297 'import_max_records_per_file' => 100,
298 'import_max_records_total_limit' => '',
299 'languages' => array('en_us' => 'English (US)'),
300 'large_scale_test' => false,
301 'list_max_entries_per_page' => 20,
302 'list_max_entries_per_subpanel' => 10,
303 'lock_default_user_name' => false,
304 'log_memory_usage' => false,
305 'portal_view' => 'single_user',
306 'resource_management' => array (
307 'special_query_limit' => 50000,
308 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
309 'default_limit' => 1000,
311 'require_accounts' => true,
312 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
314 'save_query' => 'all',
315 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
316 'showThemePicker' => true,
317 'slow_query_time_msec' => '100',
319 'time_formats' => array (
320 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
321 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
322 'tracker_max_display_length' => 15,
323 'translation_string_prefix' =>
324 return_session_value_or_default('translation_string_prefix', false),
325 'upload_badext' => array (
326 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
327 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
328 'upload_maxsize' => 30000000,
329 'import_max_execution_time' => 3600,
330 // 'use_php_code_json' => returnPhpJsonStatus(),
331 'verify_client_ip' => true,
332 'js_custom_version' => '',
333 'js_lang_version' => 1,
334 'lead_conv_activity_opt' => 'donothing',
335 'default_number_grouping_seperator' => ',',
336 'default_decimal_seperator' => '.',
337 'lock_homepage' => false,
338 'lock_subpanels' => false,
339 'max_dashlets_homepage' => '15',
340 'default_max_tabs' => '7',
341 'dashlet_display_row_options' => array('1','3','5','10'),
342 'default_subpanel_tabs' => true,
343 'default_subpanel_links' => false,
344 'default_swap_last_viewed' => false,
345 'default_swap_shortcuts' => false,
346 'default_navigation_paradigm' => 'gm',
347 'admin_access_control' => false,
348 'use_common_ml_dir' => false,
349 'common_ml_dir' => '',
352 'default_view' => 'week',
353 'show_calls_by_default' => true,
354 'show_tasks_by_default' => true,
355 'editview_width' => 990,
356 'editview_height' => 485,
357 'day_timestep' => 15,
358 'week_timestep' => 30,
359 'items_draggable' => true,
360 'items_resizable' => true,
361 'enable_repeat' => true,
362 'max_repeat_count' => 1000,
364 'passwordsetting' => empty($passwordsetting) ? array (
365 'SystemGeneratedPasswordON' => '',
366 'generatepasswordtmpl' => '',
367 'lostpasswordtmpl' => '',
368 'forgotpasswordON' => false,
369 'linkexpiration' => '1',
370 'linkexpirationtime' => '30',
371 'linkexpirationtype' => '1',
372 'systexpiration' => '0',
373 'systexpirationtime' => '',
374 'systexpirationtype' => '0',
375 'systexpirationlogin' => '',
376 ) : $passwordsetting,
377 'use_real_names' => true,
379 'search_wildcard_infront' => false,
380 'search_wildcard_char' => '%',
382 'min_retry_interval' => 30, // 30 seconds minimal job retry
383 'max_retries' => 5, // how many times to retry the job
384 'timeout' => 86400, // how long a job may spend as running before being force-failed
387 'max_cron_jobs' => 10, // max jobs per cron schedule run
388 'max_cron_runtime' => 30, // max runtime for cron jobs
389 'min_cron_interval' => 30, // minimal interval between cron jobs
393 if(!is_object($locale)) {
394 $locale = new Localization();
397 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
399 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
400 return( $sugar_config_defaults );
404 * @deprecated use SugarView::getMenu() instead
406 function load_menu($path){
409 if(file_exists($path . 'Menu.php'))
411 require($path . 'Menu.php');
413 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
415 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
417 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
419 require('custom/application/Ext/Menus/menu.ext.php');
425 * get_notify_template_file
426 * This function will return the location of the email notifications template to use
428 * @return string relative file path to email notifications template file
430 function get_notify_template_file($language){
432 * Order of operation:
433 * 1) custom version of specified language
434 * 2) stock version of specified language
435 * 3) custom version of en_us template
436 * 4) stock en_us template
439 // set $file to the base code template so it's set if none of the conditions pass
440 $file = "include/language/en_us.notify_template.html";
442 if(file_exists("custom/include/language/{$language}.notify_template.html")){
443 $file = "custom/include/language/{$language}.notify_template.html";
445 else if(file_exists("include/language/{$language}.notify_template.html")){
446 $file = "include/language/{$language}.notify_template.html";
448 else if(file_exists("custom/include/language/en_us.notify_template.html")){
449 $file = "custom/include/language/en_us.notify_template.html";
455 function sugar_config_union( $default, $override ){
456 // a little different then array_merge and array_merge_recursive. we want
457 // the second array to override the first array if the same value exists,
458 // otherwise merge the unique keys. it handles arrays of arrays recursively
459 // might be suitable for a generic array_union
460 if( !is_array( $override ) ){
463 foreach( $default as $key => $value ){
464 if( !array_key_exists($key, $override) ){
465 $override[$key] = $value;
467 else if( is_array( $key ) ){
468 $override[$key] = sugar_config_union( $value, $override[$key] );
474 function make_not_writable( $file ){
475 // Returns true if the given file/dir has been made not writable
477 if( is_file($file) || is_dir($file) ){
478 if( !is_writable($file) ){
482 $original_fileperms = fileperms($file);
484 // take away writable permissions
485 $new_fileperms = $original_fileperms & ~0x0092;
486 @sugar_chmod($file, $new_fileperms);
488 if( !is_writable($file) ){
497 /** This function returns the name of the person.
498 * It currently returns "first last". It should not put the space if either name is not available.
499 * It should not return errors if either name is not available.
500 * If no names are present, it will return ""
501 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
502 * All Rights Reserved.
503 * Contributor(s): ______________________________________..
505 function return_name($row, $first_column, $last_column)
511 if(isset($row[$first_column]))
513 $first_name = stripslashes($row[$first_column]);
516 if(isset($row[$last_column]))
518 $last_name = stripslashes($row[$last_column]);
521 $full_name = $first_name;
523 // If we have a first name and we have a last name
524 if($full_name != "" && $last_name != "")
526 // append a space, then the last name
527 $full_name .= " ".$last_name;
529 // If we have no first name, but we have a last name
530 else if($last_name != "")
532 // append the last name without the space.
533 $full_name .= $last_name;
540 function get_languages()
542 global $sugar_config;
543 $lang = $sugar_config['languages'];
544 if(!empty($sugar_config['disabled_languages'])){
545 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
546 unset($lang[$disable]);
552 function get_all_languages()
554 global $sugar_config;
555 return $sugar_config['languages'];
559 function get_language_display($key)
561 global $sugar_config;
562 return $sugar_config['languages'][$key];
565 function get_assigned_user_name($assigned_user_id, $is_group = '') {
566 static $saved_user_list = null;
568 if(empty($saved_user_list)) {
569 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
572 if(isset($saved_user_list[$assigned_user_id])) {
573 return $saved_user_list[$assigned_user_id];
580 * retrieves the user_name column value (login)
581 * @param string id GUID of user
584 function get_user_name($id) {
588 $db = DBManagerFactory::getInstance();
590 $q = "SELECT user_name FROM users WHERE id='{$id}'";
592 $a = $db->fetchByAssoc($r);
594 return (empty($a)) ? '' : $a['user_name'];
598 //TODO Update to use global cache
602 * This is a helper function to return an Array of users depending on the parameters passed into the function.
603 * This function uses the get_register_value function by default to use a caching layer where supported.
605 * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
606 * @param string $status String value indicating the status to filter users by, "Active" by default
607 * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
608 * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
609 * @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
610 * @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
611 * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
612 * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
614 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) {
616 global $sugar_config;
619 $locale = new Localization();
623 $key_name = $add_blank. $status . $user_id . $use_real_name . $user_name_filter . $portal_filter;
624 $user_array = get_register_value('user_array', $key_name);
627 if(empty($user_array)) {
628 $db = DBManagerFactory::getInstance();
629 $temp_result = Array();
630 // Including deleted users for now.
631 if (empty($status)) {
632 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$portal_filter;
635 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
638 if (!empty($user_name_filter)) {
639 $user_name_filter = $db->quote($user_name_filter);
640 $query .= " AND user_name LIKE '$user_name_filter%' ";
642 if (!empty($user_id)) {
643 $query .= " OR id='{$user_id}'";
645 $query = $query.' ORDER BY user_name ASC';
646 $GLOBALS['log']->debug("get_user_array query: $query");
647 $result = $db->query($query, true, "Error filling in user array: ");
649 if ($add_blank==true) {
650 // Add in a blank row
651 $temp_result[''] = '';
654 // Get the id and the name.
655 while($row = $db->fetchByAssoc($result)) {
656 if($use_real_name == true || showFullName()) {
657 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
658 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
660 $temp_result[$row['id']] = $row['user_name'];
663 $temp_result[$row['id']] = $row['user_name'];
667 $user_array = $temp_result;
670 set_register_value('user_array', $key_name, $temp_result);
680 * uses a different query to return a list of users than get_user_array()
681 * Used from QuickSearch.php
682 * @param args string where clause entry
683 * @return array Array of Users' details that match passed criteria
685 function getUserArrayFromFullName($args, $hide_portal_users = false) {
687 $db = DBManagerFactory::getInstance();
689 // jmorais@dri - Bug #51411
691 // Refactor the code responsible for parsing supplied $args, this way we
692 // ensure that if $args has at least one space (after trim), the $inClause
693 // will be composed by several clauses ($inClauses) inside parenthesis.
695 // Ensuring that operator precedence is respected, and avoiding
696 // inactive/deleted users to be retrieved.
699 if (strpos($args, ' ')) {
700 $inClauses = array();
702 $argArray = explode(' ', $args);
703 foreach ($argArray as $arg) {
704 $arg = $db->quote($arg);
705 $inClauses[] = "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
708 $inClause = '(' . implode('OR ', $inClauses) . ')';
711 $args = $db->quote($args);
712 $inClause = "(first_name LIKE '{$args}%' OR last_name LIKE '{$args}%')";
716 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
717 if ( $hide_portal_users ) {
718 $query .= " portal_only=0 AND ";
721 $query .= " ORDER BY last_name ASC";
723 $r = $db->query($query);
725 while($a = $db->fetchByAssoc($r)) {
726 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
734 * based on user pref then system pref
736 function showFullName() {
737 global $sugar_config;
738 global $current_user;
739 static $showFullName = null;
741 if (is_null($showFullName)) {
742 $sysPref = !empty($sugar_config['use_real_names']);
743 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
745 if($userPref != null) {
746 $showFullName = ($userPref == 'on');
748 $showFullName = $sysPref;
752 return $showFullName;
755 function clean($string, $maxLength)
757 $string = substr($string, 0, $maxLength);
758 return escapeshellcmd($string);
762 * Copy the specified request variable to the member variable of the specified object.
763 * Do no copy if the member variable is already set.
764 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
765 * All Rights Reserved.
766 * Contributor(s): ______________________________________..
768 function safe_map($request_var, & $focus, $always_copy = false)
770 safe_map_named($request_var, $focus, $request_var, $always_copy);
774 * Copy the specified request variable to the member variable of the specified object.
775 * Do no copy if the member variable is already set.
776 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
777 * All Rights Reserved.
778 * Contributor(s): ______________________________________..
780 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
782 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
783 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
784 $focus->$member_var = $_REQUEST[$request_var];
789 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
791 * @param string $language specific language to load
792 * @return array lang strings
794 function return_app_list_strings_language($language)
796 global $app_list_strings;
797 global $sugar_config;
799 $cache_key = 'app_list_strings.'.$language;
801 // Check for cached value
802 $cache_entry = sugar_cache_retrieve($cache_key);
803 if(!empty($cache_entry))
808 $default_language = $sugar_config['default_language'];
809 $temp_app_list_strings = $app_list_strings;
812 if ($language != 'en_us') {
815 if ($default_language != 'en_us' && $language != $default_language) {
816 $langs[] = $default_language;
818 $langs[] = $language;
820 $app_list_strings_array = array();
822 foreach ( $langs as $lang ) {
823 $app_list_strings = array();
824 if(file_exists("include/language/$lang.lang.php")) {
825 include("include/language/$lang.lang.php");
826 $GLOBALS['log']->info("Found language file: $lang.lang.php");
828 if(file_exists("include/language/$lang.lang.override.php")) {
829 include("include/language/$lang.lang.override.php");
830 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
832 if(file_exists("include/language/$lang.lang.php.override")) {
833 include("include/language/$lang.lang.php.override");
834 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
837 $app_list_strings_array[] = $app_list_strings;
840 $app_list_strings = array();
841 foreach ( $app_list_strings_array as $app_list_strings_item ) {
842 $app_list_strings = sugarLangArrayMerge($app_list_strings, $app_list_strings_item);
845 foreach ( $langs as $lang ) {
846 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
847 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
848 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
850 if(file_exists("custom/include/language/$lang.lang.php")) {
851 include("custom/include/language/$lang.lang.php");
852 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
856 if(!isset($app_list_strings)) {
857 $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");
861 $return_value = $app_list_strings;
862 $app_list_strings = $temp_app_list_strings;
864 sugar_cache_put($cache_key, $return_value);
866 return $return_value;
870 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
871 * $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.
872 * @param file string the language that you want include,
873 * @param app_list_strings array the golbal strings
877 function _mergeCustomAppListStrings($file , $app_list_strings){
878 $app_list_strings_original = $app_list_strings;
879 unset($app_list_strings);
880 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
881 // This way, language file can add items to save specific standard codelist from being overwritten
882 $exemptDropdowns = array();
884 if(!isset($app_list_strings) || !is_array($app_list_strings)){
885 return $app_list_strings_original;
887 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
889 // FG - bug 45525 - Specific codelists must NOT be overwritten
890 $exemptDropdowns[] = "moduleList";
891 $exemptDropdowns[] = "parent_type_display";
892 $exemptDropdowns[] = "record_type_display";
893 $exemptDropdowns[] = "record_type_display_notes";
895 foreach($app_list_strings as $key=>$value)
897 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
899 unset($app_list_strings_original["$key"]);
902 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
903 return $app_list_strings;
907 * This function retrieves an application language file and returns the array of strings included.
909 * @param string $language specific language to load
910 * @return array lang strings
912 function return_application_language($language)
914 global $app_strings, $sugar_config;
916 $cache_key = 'app_strings.'.$language;
918 // Check for cached value
919 $cache_entry = sugar_cache_retrieve($cache_key);
920 if(!empty($cache_entry))
925 $temp_app_strings = $app_strings;
926 $default_language = $sugar_config['default_language'];
929 if ($language != 'en_us') {
932 if ($default_language != 'en_us' && $language != $default_language) {
933 $langs[] = $default_language;
936 $langs[] = $language;
938 $app_strings_array = array();
940 foreach ( $langs as $lang ) {
941 $app_strings = array();
942 if(file_exists("include/language/$lang.lang.php")) {
943 include("include/language/$lang.lang.php");
944 $GLOBALS['log']->info("Found language file: $lang.lang.php");
946 if(file_exists("include/language/$lang.lang.override.php")) {
947 include("include/language/$lang.lang.override.php");
948 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
950 if(file_exists("include/language/$lang.lang.php.override")) {
951 include("include/language/$lang.lang.php.override");
952 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
954 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
955 include("custom/application/Ext/Language/$lang.lang.ext.php");
956 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
958 if(file_exists("custom/include/language/$lang.lang.php")) {
959 include("custom/include/language/$lang.lang.php");
960 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
962 $app_strings_array[] = $app_strings;
965 $app_strings = array();
966 foreach ( $app_strings_array as $app_strings_item ) {
967 $app_strings = sugarLangArrayMerge($app_strings, $app_strings_item);
970 if(!isset($app_strings)) {
971 $GLOBALS['log']->fatal("Unable to load the application language strings");
975 // If we are in debug mode for translating, turn on the prefix now!
976 if($sugar_config['translation_string_prefix']) {
977 foreach($app_strings as $entry_key=>$entry_value) {
978 $app_strings[$entry_key] = $language.' '.$entry_value;
981 if(isset($_SESSION['show_deleted'])) {
982 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
983 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
984 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
985 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
988 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
990 $return_value = $app_strings;
991 $app_strings = $temp_app_strings;
993 sugar_cache_put($cache_key, $return_value);
995 return $return_value;
999 * This function retrieves a module's language file and returns the array of strings included.
1001 * @param string $language specific language to load
1002 * @param string $module module name to load strings for
1003 * @param bool $refresh optional, true if you want to rebuild the language strings
1004 * @return array lang strings
1006 function return_module_language($language, $module, $refresh=false)
1008 global $mod_strings;
1009 global $sugar_config;
1010 global $currentModule;
1012 // Jenny - Bug 8119: Need to check if $module is not empty
1013 if (empty($module)) {
1014 $stack = debug_backtrace();
1015 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
1021 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1022 // Check for cached value
1023 $cache_entry = sugar_cache_retrieve($cache_key);
1024 if(!empty($cache_entry) && is_array($cache_entry))
1026 return $cache_entry;
1029 // Store the current mod strings for later
1030 $temp_mod_strings = $mod_strings;
1031 $loaded_mod_strings = array();
1032 $language_used = $language;
1033 $default_language = $sugar_config['default_language'];
1035 if(empty($language)) {
1036 $language = $default_language;
1039 // Bug 21559 - So we can get all the strings defined in the template, refresh
1040 // the vardefs file if the cached language file doesn't exist.
1041 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1042 && !empty($GLOBALS['beanList'][$module])){
1043 $object = BeanFactory::getObjectName($module);
1044 VardefManager::refreshVardefs($module,$object);
1047 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1049 // cn: bug 6048 - merge en_us with requested language
1050 if($language != $sugar_config['default_language'])
1051 $loaded_mod_strings = sugarLangArrayMerge(
1052 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1056 // Load in en_us strings by default
1057 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1058 $loaded_mod_strings = sugarLangArrayMerge(
1059 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1063 // If we are in debug mode for translating, turn on the prefix now!
1064 if($sugar_config['translation_string_prefix']) {
1065 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1066 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1070 $return_value = $loaded_mod_strings;
1071 if(!isset($mod_strings)){
1072 $mod_strings = $return_value;
1075 $mod_strings = $temp_mod_strings;
1077 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1078 sugar_cache_put($cache_key, $return_value);
1079 return $return_value;
1083 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1084 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1085 * All Rights Reserved.
1086 * Contributor(s): ______________________________________..
1087 * If you are using the current language, do not call this function unless you are loading it for the first time */
1088 function return_mod_list_strings_language($language,$module) {
1089 global $mod_list_strings;
1090 global $sugar_config;
1091 global $currentModule;
1093 $cache_key = "mod_list_str_lang.".$language.$module;
1095 // Check for cached value
1096 $cache_entry = sugar_cache_retrieve($cache_key);
1097 if(!empty($cache_entry))
1099 return $cache_entry;
1102 $language_used = $language;
1103 $temp_mod_list_strings = $mod_list_strings;
1104 $default_language = $sugar_config['default_language'];
1106 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1107 return $mod_list_strings;
1110 // cn: bug 6351 - include en_us if file langpack not available
1111 // cn: bug 6048 - merge en_us with requested language
1112 include("modules/$module/language/en_us.lang.php");
1113 $en_mod_list_strings = array();
1114 if($language_used != $default_language)
1115 $en_mod_list_strings = $mod_list_strings;
1117 if(file_exists("modules/$module/language/$language.lang.php")) {
1118 include("modules/$module/language/$language.lang.php");
1121 if(file_exists("modules/$module/language/$language.lang.override.php")){
1122 include("modules/$module/language/$language.lang.override.php");
1125 if(file_exists("modules/$module/language/$language.lang.php.override")){
1126 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1127 include("modules/$module/language/$language.lang.php.override");
1130 // cn: bug 6048 - merge en_us with requested language
1131 $mod_list_strings = sugarLangArrayMerge($en_mod_list_strings, $mod_list_strings);
1133 // if we still don't have a language pack, then log an error
1134 if(!isset($mod_list_strings)) {
1135 $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})");
1139 $return_value = $mod_list_strings;
1140 $mod_list_strings = $temp_mod_list_strings;
1142 sugar_cache_put($cache_key, $return_value);
1143 return $return_value;
1147 /** This function retrieves a theme's language file and returns the array of strings included.
1148 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1149 * All Rights Reserved.
1150 * Contributor(s): ______________________________________..
1152 function return_theme_language($language, $theme)
1154 global $mod_strings, $sugar_config, $current_language;
1156 $language_used = $language;
1157 $default_language = $sugar_config['default_language'];
1159 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1160 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1161 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1163 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1164 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";
1165 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1167 if(!isset($theme_strings))
1169 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1170 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1171 $language_used = $default_language;
1174 if(!isset($theme_strings))
1176 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1180 // If we are in debug mode for translating, turn on the prefix now!
1181 if($sugar_config['translation_string_prefix'])
1183 foreach($theme_strings as $entry_key=>$entry_value)
1185 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1189 return $theme_strings;
1194 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1195 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1196 * All Rights Reserved.
1197 * Contributor(s): ______________________________________..
1199 function return_session_value_or_default($varname, $default)
1201 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1203 return $_SESSION[$varname];
1210 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1211 * 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.
1212 * @param &$where_clauses - The array to append the clause to
1213 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1214 * @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.
1215 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1216 * All Rights Reserved.
1217 * Contributor(s): ______________________________________..
1219 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1221 if($SQL_name == null)
1223 $SQL_name = $variable_name;
1226 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1228 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1233 * Generate the appropriate SQL based on the where clauses.
1234 * @param $where_clauses - An Array of individual where clauses stored as strings
1235 * @returns string where_clause - The final SQL where clause to be executed.
1236 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1237 * All Rights Reserved.
1238 * Contributor(s): ______________________________________..
1240 function generate_where_statement($where_clauses)
1243 foreach($where_clauses as $clause)
1250 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1255 * determines if a passed string matches the criteria for a Sugar GUID
1256 * @param string $guid
1257 * @return bool False on failure
1259 function is_guid($guid) {
1260 if(strlen($guid) != 36) {
1264 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1273 * A temporary method of generating GUIDs of the correct format for our DB.
1274 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1276 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1277 * All Rights Reserved.
1278 * Contributor(s): ______________________________________..
1280 function create_guid()
1282 $microTime = microtime();
1283 list($a_dec, $a_sec) = explode(" ", $microTime);
1285 $dec_hex = dechex($a_dec* 1000000);
1286 $sec_hex = dechex($a_sec);
1288 ensure_length($dec_hex, 5);
1289 ensure_length($sec_hex, 6);
1293 $guid .= create_guid_section(3);
1295 $guid .= create_guid_section(4);
1297 $guid .= create_guid_section(4);
1299 $guid .= create_guid_section(4);
1302 $guid .= create_guid_section(6);
1308 function create_guid_section($characters)
1311 for($i=0; $i<$characters; $i++)
1313 $return .= dechex(mt_rand(0,15));
1318 function ensure_length(&$string, $length)
1320 $strlen = strlen($string);
1321 if($strlen < $length)
1323 $string = str_pad($string,$length,"0");
1325 else if($strlen > $length)
1327 $string = substr($string, 0, $length);
1331 function microtime_diff($a, $b) {
1332 list($a_dec, $a_sec) = explode(" ", $a);
1333 list($b_dec, $b_sec) = explode(" ", $b);
1334 return $b_sec - $a_sec + $b_dec - $a_dec;
1337 // check if Studio is displayed.
1338 function displayStudioForCurrentUser()
1340 global $current_user;
1341 if ( $current_user->isAdmin() ) {
1351 function displayWorkflowForCurrentUser()
1353 $_SESSION['display_workflow_for_user'] = false;
1357 // return an array with all modules where the user is an admin.
1358 function get_admin_modules_for_user($user) {
1359 $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");
1366 return($user->getDeveloperModules());
1370 function get_workflow_admin_modules_for_user($user){
1371 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1372 return $_SESSION['get_workflow_admin_modules_for_user'];
1376 $workflow_mod_list = array();
1377 foreach($moduleList as $module){
1378 $workflow_mod_list[$module] = $module;
1381 // This list is taken from teh previous version of workflow_utils.php
1382 $workflow_mod_list['Tasks'] = "Tasks";
1383 $workflow_mod_list['Calls'] = "Calls";
1384 $workflow_mod_list['Meetings'] = "Meetings";
1385 $workflow_mod_list['Notes'] = "Notes";
1386 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1387 $workflow_mod_list['Leads'] = "Leads";
1388 $workflow_mod_list['Opportunities'] = "Opportunities";
1391 $workflow_admin_modules = array();
1393 return $workflow_admin_modules;
1395 $actions = ACLAction::getUserActions($user->id);
1396 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1397 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1398 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1399 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1401 foreach ($workflow_mod_list as $key=>$val) {
1402 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1403 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1404 ($user->isDeveloperForModule($key))) {
1405 $workflow_admin_modules[$key] = $val;
1408 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1409 return ($workflow_admin_modules);
1412 // Check if user is admin for at least one module.
1413 function is_admin_for_any_module($user) {
1417 if($user->isAdmin()) {
1424 // Check if user is admin for a specific module.
1425 function is_admin_for_module($user,$module) {
1426 if (!isset($user)) {
1429 if ($user->isAdmin()) {
1437 * Check if user id belongs to a system admin.
1438 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1439 * All Rights Reserved.
1440 * Contributor(s): ______________________________________..
1442 function is_admin($user) {
1447 return $user->isAdmin();
1451 * Return the display name for a theme if it exists.
1452 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1453 * All Rights Reserved.
1454 * Contributor(s): ______________________________________..
1456 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1458 function get_theme_display($theme)
1460 return SugarThemeRegistry::get($theme)->name;
1464 * Return an array of directory names.
1465 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1466 * All Rights Reserved.
1467 * Contributor(s): ______________________________________..
1469 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1471 function get_themes()
1473 return SugarThemeRegistry::availableThemes();
1477 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1478 * Create HTML to display select options in a dropdown list. To be used inside
1479 * of a select statement in a form.
1480 * param $option_list - the array of strings to that contains the option list
1481 * param $selected - the string which contains the default value
1482 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1483 * All Rights Reserved.
1484 * Contributor(s): ______________________________________..
1486 function get_select_options ($option_list, $selected) {
1487 return get_select_options_with_id($option_list, $selected);
1491 * Create HTML to display select options in a dropdown list. To be used inside
1492 * 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.
1493 * param $option_list - the array of strings to that contains the option list
1494 * param $selected - the string which contains the default value
1495 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1496 * All Rights Reserved.
1497 * Contributor(s): ______________________________________..
1499 function get_select_options_with_id ($option_list, $selected_key) {
1500 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1505 * Create HTML to display select options in a dropdown list. To be used inside
1506 * 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.
1507 * param $label_list - the array of strings to that contains the option list
1508 * param $key_list - the array of strings to that contains the values list
1509 * param $selected - the string which contains the default value
1510 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1511 * All Rights Reserved.
1512 * Contributor(s): ______________________________________..
1514 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1515 global $app_strings;
1516 $select_options = "";
1518 //for setting null selection values to human readable --None--
1519 $pattern = "/'0?'></";
1520 $replacement = "''>".$app_strings['LBL_NONE']."<";
1522 $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
1525 if (empty($key_list)) $key_list = array();
1526 //create the type dropdown domain and set the selected value if $opp value already exists
1527 foreach ($key_list as $option_key=>$option_value) {
1529 $selected_string = '';
1530 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1531 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1532 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1534 $selected_string = 'selected ';
1537 $html_value = $option_key;
1539 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1541 $select_options = preg_replace($pattern, $replacement, $select_options);
1542 return $select_options;
1547 * Call this method instead of die().
1548 * Then we call the die method with the error message that is passed in.
1550 function sugar_die($error_message)
1554 die($error_message);
1559 * Create javascript to clear values of all elements in a form.
1560 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1561 * All Rights Reserved.
1562 * Contributor(s): ______________________________________..
1564 function get_clear_form_js () {
1565 $the_script = <<<EOQ
1566 <script type="text/javascript" language="JavaScript">
1567 function clear_form(form) {
1568 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1569 if(typeof(form.advanced) != 'undefined'){
1570 newLoc += '&advanced=' + form.advanced.value;
1572 document.location.href= newLoc;
1581 * Create javascript to set the cursor focus to specific field in a form
1582 * when the screen is rendered. The field name is currently hardcoded into the
1584 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1585 * All Rights Reserved.
1586 * Contributor(s): ______________________________________..
1588 function get_set_focus_js () {
1589 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1590 $the_script = <<<EOQ
1591 <script type="text/javascript" language="JavaScript">
1593 function set_focus() {
1594 if (document.forms.length > 0) {
1595 for (i = 0; i < document.forms.length; i++) {
1596 for (j = 0; j < document.forms[i].elements.length; j++) {
1597 var field = document.forms[i].elements[j];
1598 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1599 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1601 if (field.type == "text") {
1618 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1619 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1620 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1621 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1622 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1623 * the first - so the array is sorted by the last given column first, then the one before ...
1624 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1625 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1626 * All Rights Reserved.
1627 * Contributor(s): ______________________________________..
1629 function array_csort() {
1630 $args = func_get_args();
1631 $marray = array_shift($args);
1634 $msortline = "return(array_multisort(";
1635 foreach ($args as $arg) {
1637 if (is_string($arg)) {
1638 foreach ($marray as $row) {
1639 $sortarr[$i][] = $row[$arg];
1642 $sortarr[$i] = $arg;
1644 $msortline .= "\$sortarr[".$i."],";
1646 $msortline .= "\$marray));";
1653 * Converts localized date format string to jscalendar format
1654 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1655 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1656 * All Rights Reserved.
1657 * Contributor(s): ______________________________________..
1659 function parse_calendardate($local_format) {
1660 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1661 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1662 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1669 function translate($string, $mod='', $selectedValue=''){
1670 //$test_start = microtime();
1671 //static $mod_strings_results = array();
1673 global $current_language;
1675 if(isset($_REQUEST['login_language'])){
1676 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1678 $mod_strings = return_module_language($current_language, $mod);
1680 echo "Language is <pre>" . $mod_strings . "</pre>";
1683 global $mod_strings;
1687 global $app_strings, $app_list_strings;
1689 if (isset($mod_strings[$string]))
1690 $returnValue = $mod_strings[$string];
1691 else if (isset($app_strings[$string]))
1692 $returnValue = $app_strings[$string];
1693 else if (isset($app_list_strings[$string]))
1694 $returnValue = $app_list_strings[$string];
1695 else if (isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1696 $returnValue = $app_list_strings['moduleList'][$string];
1699 //$test_end = microtime();
1701 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1703 // echo("translate results:");
1705 // $total_strings = 0;
1706 // foreach($mod_strings_results as $key=>$value)
1708 // echo("Module $key \t\t time $value \t\t<br>");
1709 // $total_time += $value;
1712 // echo("Total time: $total_time<br>");
1716 if(empty($returnValue)){
1720 // Bug 48996 - Custom enums with '0' value were not returning because of empty check
1721 // Added a numeric 0 checker to the conditional to allow 0 value indexed to pass
1722 if(is_array($returnValue) && (!empty($selectedValue) || (is_numeric($selectedValue) && $selectedValue == 0)) && isset($returnValue[$selectedValue]) ){
1723 return $returnValue[$selectedValue];
1726 return $returnValue;
1729 function unTranslateNum($num) {
1731 static $num_grp_sep;
1732 global $current_user, $sugar_config;
1734 if($dec_sep == null) {
1735 $user_dec_sep = $current_user->getPreference('dec_sep');
1736 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1738 if($num_grp_sep == null) {
1739 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1740 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1743 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1744 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1749 function add_http($url) {
1750 if(!preg_match("@://@i", $url)) {
1752 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1756 return "{$scheme}://{$url}";
1763 * returns a default array of XSS tags to clean
1766 function getDefaultXssTags() {
1768 "applet" => "applet",
1773 "frameset" => "frameset",
1774 "iframe" => "iframe",
1775 "import" => "\?import",
1778 "object" => "object",
1779 "script" => "script",
1783 $ret = base64_encode(serialize($tmp));
1789 * Remove potential xss vectors from strings
1790 * @param string str String to search for XSS attack vectors
1794 function remove_xss($str)
1796 return SugarCleaner::cleanHtml($str, false);
1800 * Detects typical XSS attack patterns
1802 * @param string str String to search for XSS attack vectors
1803 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1804 * @return array Array of matches, empty on clean string
1806 function clean_xss($str, $cleanImg=true) {
1807 global $sugar_config;
1809 if(empty($sugar_config['email_xss']))
1810 $sugar_config['email_xss'] = getDefaultXssTags();
1812 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1814 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1815 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1816 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1817 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1819 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1820 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1821 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1822 $css_url = '#url\(.*\.\w+\)#';
1824 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1826 $tagmatches = array();
1828 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1829 foreach($tagmatches[1] as $no => $tag) {
1830 if(in_array($tag, $xsstags)) {
1831 // dangerous tag - take out whole
1832 $matches[] = $tagmatches[0][$no];
1835 $attrmatch = array();
1836 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1837 if(!empty($attrmatch[0])) {
1838 $matches = array_merge($matches, $attrmatch[0]);
1842 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1845 $matches = array_merge($matches,
1846 xss_check_pattern($imgsrc_regex, $str)
1850 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1851 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1853 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1854 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1855 // normalize whitelist
1856 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1857 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1860 foreach($cssUrlMatches[0] as $match) {
1861 $domain = strtolower(substr(strstr($match, "://"), 3));
1862 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1864 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1865 $matches[] = $match;
1870 $matches = array_merge($matches, $cssUrlMatches[0]);
1877 * Helper function used by clean_xss() to parse for known-bad vectors
1878 * @param string pattern Regex pattern to use
1879 * @param string str String to parse for badness
1882 function xss_check_pattern($pattern, $str) {
1883 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1888 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1890 * @param string $str
1891 * @param string $filter which corresponds to a regular expression to use; choices are:
1892 * "STANDARD" ( default )
1902 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1904 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1906 global $sugar_config;
1909 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1910 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1911 "FILE" => '#[^A-Z0-9\-_\.]#i',
1912 "NUMBER" => '#[^0-9\-]#i',
1913 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1914 "PATH_NO_URL" => '#://#i',
1915 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1916 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1917 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1918 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1921 if (preg_match($filters[$filter], $str)) {
1922 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1923 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1925 if ( $dieOnBadData ) {
1926 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1935 function clean_special_arguments() {
1936 if(isset($_SERVER['PHP_SELF'])) {
1937 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1939 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1940 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1941 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1942 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1943 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1944 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1945 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1946 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1947 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1948 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1949 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1950 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1951 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1952 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1953 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1954 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1955 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1956 clean_superglobals('offset', 'ALPHANUM');
1957 clean_superglobals('return_action');
1958 clean_superglobals('return_module');
1963 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1965 function clean_superglobals($key, $filter = 'STANDARD') {
1966 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1967 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1968 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1971 function set_superglobals($key, $val){
1973 $_POST[$key] = $val;
1974 $_REQUEST[$key] = $val;
1977 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1978 function clean_incoming_data() {
1979 global $sugar_config;
1980 global $RAW_REQUEST;
1982 if(get_magic_quotes_gpc()) {
1983 // magic quotes screw up data, we'd have to clean up
1984 $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1986 $RAW_REQUEST = $_REQUEST;
1989 if (get_magic_quotes_gpc() == 1) {
1990 $req = array_map("preprocess_param", $_REQUEST);
1991 $post = array_map("preprocess_param", $_POST);
1992 $get = array_map("preprocess_param", $_GET);
1995 $req = array_map("securexss", $_REQUEST);
1996 $post = array_map("securexss", $_POST);
1997 $get = array_map("securexss", $_GET);
2000 // PHP cannot stomp out superglobals reliably
2001 foreach($post as $k => $v) { $_POST[$k] = $v; }
2002 foreach($get as $k => $v) { $_GET[$k] = $v; }
2003 foreach($req as $k => $v) {
2006 //ensure the keys are safe as well. If mbstring encoding translation is on, the post keys don't
2007 //get translated, so scrub the data but don't die
2008 if(ini_get('mbstring.encoding_translation')==='1'){
2009 securexsskey($k,false);
2011 securexsskey($k,true);
2015 // Any additional variables that need to be cleaned should be added here
2016 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
2017 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
2018 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
2019 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
2020 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
2021 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
2022 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
2023 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
2024 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
2025 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
2026 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
2027 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
2028 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
2030 if(isset($_REQUEST['lvso'])){
2031 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
2033 // Clean "offset" and "order_by" parameters in URL
2034 foreach ($_REQUEST as $key => $val) {
2035 if (str_end($key, "_offset")) {
2036 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
2037 set_superglobals($key, $_REQUEST[$key]);
2039 elseif (str_end($key, "_ORDER_BY")) {
2040 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2041 set_superglobals($key, $_REQUEST[$key]);
2049 // Returns TRUE if $str begins with $begin
2050 function str_begin($str, $begin) {
2051 return (substr($str, 0, strlen($begin)) == $begin);
2054 // Returns TRUE if $str ends with $end
2055 function str_end($str, $end) {
2056 return (substr($str, strlen($str) - strlen($end)) == $end);
2059 function securexss($value) {
2060 if(is_array($value)){
2062 foreach($value as $key=>$val){
2063 $new[$key] = securexss($val);
2067 static $xss_cleanup= array(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2068 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2069 $value = preg_replace('/javascript:/i', 'java script:', $value);
2070 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2073 function securexsskey($value, $die=true){
2074 global $sugar_config;
2076 preg_match('/[\'"<>]/', $value, $matches);
2077 if(!empty($matches)){
2079 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2081 unset($_REQUEST[$value]);
2082 unset($_POST[$value]);
2083 unset($_GET[$value]);
2088 function preprocess_param($value){
2089 if(is_string($value)){
2090 if(get_magic_quotes_gpc() == 1){
2091 $value = stripslashes($value);
2094 $value = securexss($value);
2100 function cleanup_slashes($value)
2102 if(is_string($value)) return stripslashes($value);
2107 function set_register_value($category, $name, $value){
2108 return sugar_cache_put("{$category}:{$name}", $value);
2111 function get_register_value($category,$name){
2112 return sugar_cache_retrieve("{$category}:{$name}");
2115 function clear_register_value($category,$name){
2116 return sugar_cache_clear("{$category}:{$name}");
2118 // this function cleans id's when being imported
2119 function convert_id($string)
2121 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2123 // single quotes are essential here,
2124 // or alternative escape all $ as \$
2126 'return ord($matches[0]);'
2131 * @deprecated use SugarTheme::getImage()
2133 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2135 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2138 * @deprecated use SugarTheme::getImageURL()
2140 function getImagePath($image_name)
2142 return SugarThemeRegistry::current()->getImageURL($image_name);
2145 function getWebPath($relative_path){
2146 //if it has a :// then it isn't a relative path
2147 if(substr_count($relative_path, '://') > 0) return $relative_path;
2148 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2149 return $relative_path;
2152 function getVersionedPath($path, $additional_attrs='')
2154 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2155 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2156 if(inDeveloperMode()) {
2158 if(empty($rand)) $rand = mt_rand();
2163 if(is_array($additional_attrs)) {
2164 $additional_attrs = join("|",$additional_attrs);
2166 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2167 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2168 // remove / - it confuses some parsers
2169 $str = strtr($str, '/+', '-_');
2170 if(empty($path)) return $str;
2172 return $path . "?v=$str";
2175 function getVersionedScript($path, $additional_attrs='')
2177 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2180 function getJSPath($relative_path, $additional_attrs='')
2182 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2183 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2186 function getSWFPath($relative_path, $additional_params=''){
2187 $path = $relative_path;
2188 if (!empty($additional_params)){
2189 $path .= '?' . $additional_params;
2191 if (defined('TEMPLATE_URL')){
2192 $path = TEMPLATE_URL . '/' . $path;
2201 function getSQLDate($date_str)
2203 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2205 if ( strlen($match[2]) == 1)
2207 $match[2] = "0".$match[2];
2209 if ( strlen($match[1]) == 1)
2211 $match[1] = "0".$match[1];
2213 return "{$match[3]}-{$match[1]}-{$match[2]}";
2215 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2217 if ( strlen($match[2]) == 1)
2219 $match[2] = "0".$match[2];
2221 if ( strlen($match[1]) == 1)
2223 $match[1] = "0".$match[1];
2225 return "{$match[3]}-{$match[1]}-{$match[2]}";
2233 function clone_history(&$db, $from_id,$to_id, $to_type)
2238 require_once('include/upload_file.php');
2239 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2241 $location=array('Email'=>"modules/Emails/Email.php",
2242 'Call'=>"modules/Calls/Call.php",
2243 'Meeting'=>"modules/Meetings/Meeting.php",
2244 'Note'=>"modules/Notes/Note.php",
2245 'Tasks'=>"modules/Tasks/Task.php",
2249 foreach($tables as $table=>$bean_class)
2252 if (!class_exists($bean_class))
2254 require_once($location[$bean_class]);
2257 $bProcessingNotes=false;
2258 if ($table=='notes')
2260 $bProcessingNotes=true;
2262 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2263 $results = $db->query($query);
2264 while($row = $db->fetchByAssoc($results))
2266 //retrieve existing record.
2267 $bean= new $bean_class();
2268 $bean->retrieve($row['id']);
2269 //process for new instance.
2270 if ($bProcessingNotes)
2272 $old_note_id=$row['id'];
2273 $old_filename=$bean->filename;
2276 $bean->parent_id=$to_id;
2277 $bean->parent_type=$to_type;
2278 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2280 $bean->contact_id=$to_id;
2282 $bean->update_date_modified = false;
2283 $bean->update_modified_by = false;
2284 if(isset($bean->date_modified))
2285 $bean->date_modified = $timedate->to_db($bean->date_modified);
2286 if(isset($bean->date_entered))
2287 $bean->date_entered = $timedate->to_db($bean->date_entered);
2289 $new_id=$bean->save();
2291 //duplicate the file now. for notes.
2292 if ($bProcessingNotes && !empty($old_filename))
2294 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2296 //reset the values needed for attachment duplication.
2303 function values_to_keys($array)
2305 $new_array = array();
2306 if(!is_array($array))
2310 foreach($array as $arr){
2311 $new_array[$arr] = $arr;
2316 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2318 foreach($tables as $table)
2321 if ($table == 'emails_beans') {
2322 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2324 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2326 $results = $db->query($query);
2327 while($row = $db->fetchByAssoc($results))
2329 $query = "INSERT INTO $table ";
2332 $row[$from_column] = $to_id;
2333 $row['id'] = create_guid();
2334 if ($table=='emails_beans') {
2335 $row['bean_module'] =='Contacts';
2338 foreach($row as $name=>$value)
2344 $values .= "'$value'";
2347 $names .= ', '. $name;
2348 $values .= ", '$value'";
2351 $query .= "($names) VALUES ($values)";
2357 function get_unlinked_email_query($type, $bean) {
2358 global $current_user;
2360 $return_array['select']='SELECT emails.id ';
2361 $return_array['from']='FROM emails ';
2362 $return_array['where']="";
2363 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2365 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2366 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2367 where eear.deleted=0 and eear.email_id not in
2368 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2369 ) derivedemails on derivedemails.email_id = emails.id";
2370 $return_array['join_tables'][0] = '';
2372 if (isset($type) and !empty($type['return_as_array'])) {
2373 return $return_array;
2376 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2379 function get_emails_by_assign_or_link($params)
2381 $relation = $params['link'];
2382 $bean = $GLOBALS['app']->controller->bean;
2383 if(empty($bean->$relation)) {
2384 $bean->load_relationship($relation);
2386 if(empty($bean->$relation)) {
2387 $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
2390 $rel_module = $bean->$relation->getRelatedModuleName();
2391 $rel_join = $bean->$relation->getJoin(array(
2392 'join_table_alias' => 'link_bean',
2393 'join_table_link_alias' => 'linkt',
2395 $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
2396 $return_array['select']='SELECT emails.id ';
2397 $return_array['from'] = "FROM emails ";
2398 $return_array['join'] = " INNER JOIN (".
2399 // directly assigned emails
2400 "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 ".
2402 // Assigned to contacts
2403 "select DISTINCT eb.email_id, 'contact' source FROM emails_beans eb
2404 $rel_join AND link_bean.id = eb.bean_id
2405 where eb.bean_module = '$rel_module' AND eb.deleted=0".
2407 // Related by directly by email
2408 "select DISTINCT eear.email_id, 'relate' source from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2409 ON eabr.bean_id ='{$bean->id}' AND eabr.bean_module = '{$bean->module_dir}' AND
2410 eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0".
2412 // Related by email to linked contact
2413 "select DISTINCT eear.email_id, 'relate_contact' source FROM emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2414 ON eabr.email_address_id=eear.email_address_id AND eabr.bean_module = '$rel_module' AND eabr.deleted=0
2415 $rel_join AND link_bean.id = eabr.bean_id
2416 where eear.deleted=0".
2417 ") email_ids ON emails.id=email_ids.email_id ";
2418 $return_array['where']=" WHERE emails.deleted=0 ";
2420 //$return_array['join'] = '';
2421 $return_array['join_tables'][0] = '';
2423 if($bean->object_name == "Case" && !empty($bean->case_number)) {
2424 $where = str_replace("%1", $bean->case_number, $bean->getEmailSubjectMacro());
2425 $return_array["where"] .= "\n AND (email_ids.source = 'direct' OR emails.name LIKE '%$where%')";
2428 return $return_array;
2432 * Check to see if the number is empty or non-zero
2436 function number_empty($value)
2438 return empty($value) && $value != '0';
2441 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2444 require_once($beanFiles[$bean_name]);
2445 $focus = new $bean_name();
2446 $user_array = array();
2448 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2449 $user_array = get_register_value('select_array', $key );
2453 $db = DBManagerFactory::getInstance();
2455 $temp_result = Array();
2456 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2460 $query .= $where." AND ";
2463 $query .= " {$focus->table_name}.deleted=0";
2465 if ( $order_by != '')
2467 $query .= " order by {$focus->table_name}.{$order_by}";
2470 $GLOBALS['log']->debug("get_user_array query: $query");
2471 $result = $db->query($query, true, "Error filling in user array: ");
2473 if ($add_blank==true){
2474 // Add in a blank row
2475 if($blank_is_none == true) { // set 'blank row' to "--None--"
2476 global $app_strings;
2477 $temp_result[''] = $app_strings['LBL_NONE'];
2479 $temp_result[''] = '';
2483 // Get the id and the name.
2484 while($row = $db->fetchByAssoc($result))
2486 $temp_result[$row['id']] = $row['display'];
2489 $user_array = $temp_result;
2490 set_register_value('select_array', $key ,$temp_result);
2499 * @param unknown_type $listArray
2501 // function parse_list_modules
2502 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2503 function parse_list_modules(&$listArray)
2505 global $modListHeader;
2506 $returnArray = array();
2508 foreach($listArray as $optionName => $optionVal)
2510 if(array_key_exists($optionName, $modListHeader))
2512 $returnArray[$optionName] = $optionVal;
2515 // special case for projects
2516 if(array_key_exists('Project', $modListHeader))
2518 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2521 $acldenied = ACLController::disabledModuleList($listArray,false);
2522 foreach($acldenied as $denied){
2523 unset($returnArray[$denied]);
2525 asort($returnArray);
2527 return $returnArray;
2530 function display_notice($msg = false){
2531 global $error_notice;
2532 //no error notice - lets just display the error to the user
2533 if(!isset($error_notice)){
2534 echo '<br>'.$msg . '<br>';
2536 $error_notice .= $msg . '<br>';
2540 /* checks if it is a number that at least has the plus at the beginning.
2542 function skype_formatted($number){
2543 //kbrill - BUG #15375
2544 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2547 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2549 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2552 function format_skype($number) {
2553 return preg_replace('/[^\+0-9]/','',$number);
2556 function insert_charset_header() {
2557 header('Content-Type: text/html; charset=UTF-8');
2560 function getCurrentURL()
2563 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2568 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2572 function javascript_escape($str) {
2575 for($i = 0; $i < strlen($str); $i++) {
2577 if(ord(substr($str, $i, 1))==10){
2579 }elseif(ord(substr($str, $i, 1))==13){
2583 $new_str .= $str{$i};
2587 $new_str = str_replace("'", "\\'", $new_str);
2592 function js_escape($str, $keep=true){
2593 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2596 $str = javascript_escape($str);
2599 $str = str_replace("'", " ", $str);
2600 $str = str_replace('"', " ", $str);
2605 //end function js_escape
2608 function br2nl($str) {
2609 $regex = "#<[^>]+br.+?>#i";
2610 preg_match_all($regex, $str, $matches);
2612 foreach($matches[0] as $match) {
2613 $str = str_replace($match, "<br>", $str);
2616 $brs = array('<br>','<br/>', '<br />');
2617 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2618 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2619 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2620 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2626 * Private helper function for displaying the contents of a given variable.
2627 * This function is only intended to be used for SugarCRM internal development.
2628 * The ppd stands for Pre Print Die.
2630 function _ppd($mixed)
2636 * Private helper function for displaying the contents of a given variable in
2637 * the Logger. This function is only intended to be used for SugarCRM internal
2638 * development. The pp stands for Pre Print.
2639 * @param $mixed var to print_r()
2640 * @param $die boolean end script flow
2641 * @param $displayStackTrace also show stack trace
2643 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2644 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2646 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2650 $mix = print_r($mixed, true); // send print_r() output to $mix
2651 $stack = debug_backtrace();
2653 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2654 $GLOBALS['log']->$loglevel($mix);
2655 if($displayStackTrace) {
2656 foreach($stack as $position) {
2657 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2661 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2662 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2670 * private helper function to quickly show the major, direct, field attributes of a given bean.
2671 * The ppf stands for Pre[formatted] Print Focus [object]
2672 * @param object bean The focus bean
2674 function _ppf($bean, $die=false) {
2680 * Private helper function for displaying the contents of a given variable.
2681 * This function is only intended to be used for SugarCRM internal development.
2682 * The pp stands for Pre Print.
2684 function _pp($mixed)
2689 * Private helper function for displaying the contents of a given variable.
2690 * This function is only intended to be used for SugarCRM internal development.
2691 * The pp stands for Pre Print.
2693 function _pstack_trace($mixed=NULL)
2698 * Private helper function for displaying the contents of a given variable.
2699 * This function is only intended to be used for SugarCRM internal development.
2700 * The pp stands for Pre Print Trace.
2702 function _ppt($mixed, $textOnly=false)
2707 * Private helper function for displaying the contents of a given variable.
2708 * This function is only intended to be used for SugarCRM internal development.
2709 * The pp stands for Pre Print Trace Die.
2711 function _pptd($mixed)
2716 * Private helper function for decoding javascript UTF8
2717 * This function is only intended to be used for SugarCRM internal development.
2719 function decodeJavascriptUTF8($str) {
2723 * Will check if a given PHP version string is supported (tested on this ver),
2724 * unsupported (results unknown), or invalid (something will break on this
2725 * ver). Do not pass in any pararameter to default to a check against the
2726 * current environment's PHP version.
2728 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2730 function check_php_version($sys_php_version = '') {
2731 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2732 // versions below $min_considered_php_version considered invalid by default,
2733 // versions equal to or above this ver will be considered depending
2734 // on the rules that follow
2735 $min_considered_php_version = '5.2.1';
2737 // only the supported versions,
2738 // should be mutually exclusive with $invalid_php_versions
2739 $supported_php_versions = array (
2740 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2743 // invalid versions above the $min_considered_php_version,
2744 // should be mutually exclusive with $supported_php_versions
2746 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2747 $invalid_php_versions = array('5.2.7');
2749 // default unsupported
2752 // versions below $min_considered_php_version are invalid
2753 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2757 // supported version check overrides default unsupported
2758 foreach($supported_php_versions as $ver) {
2759 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2765 // invalid version check overrides default unsupported
2766 foreach($invalid_php_versions as $ver) {
2767 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2773 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2774 //and the php version contains 'rh' characters
2775 if(strpos($sys_php_version, 'rh') !== false) {
2783 * Will check if a given IIS version string is supported (tested on this ver),
2784 * unsupported (results unknown), or invalid (something will break on this
2787 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2789 function check_iis_version($sys_iis_version = '') {
2791 $server_software = $_SERVER["SERVER_SOFTWARE"];
2793 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2794 $iis_version = $out[1][0];
2796 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2798 // versions below $min_considered_iis_version considered invalid by default,
2799 // versions equal to or above this ver will be considered depending
2800 // on the rules that follow
2801 $min_considered_iis_version = '6.0';
2803 // only the supported versions,
2804 // should be mutually exclusive with $invalid_iis_versions
2805 $supported_iis_versions = array ('6.0', '7.0',);
2806 $unsupported_iis_versions = array();
2807 $invalid_iis_versions = array('5.0',);
2809 // default unsupported
2812 // versions below $min_considered_iis_version are invalid
2813 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2817 // supported version check overrides default unsupported
2818 foreach($supported_iis_versions as $ver) {
2819 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2825 // unsupported version check overrides default unsupported
2826 foreach($unsupported_iis_versions as $ver) {
2827 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2833 // invalid version check overrides default unsupported
2834 foreach($invalid_iis_versions as $ver) {
2835 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2844 function pre_login_check(){
2845 global $action, $login_error;
2846 if(!empty($action)&& $action == 'Login'){
2848 if(!empty($login_error)){
2849 $login_error = htmlentities($login_error);
2850 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2851 $_SESSION['login_error'] = $login_error;
2853 function set_focus() {}
2854 if(document.getElementById("post_error")) {
2855 document.getElementById("post_error").innerHTML="'. $login_error. '";
2856 document.getElementById("cant_login").value=1;
2857 document.getElementById("login_button").disabled = true;
2858 document.getElementById("user_name").disabled = true;
2859 //document.getElementById("user_password").disabled = true;
2868 function sugar_cleanup($exit = false) {
2869 static $called = false;
2872 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2873 chdir(realpath(dirname(__FILE__) . '/..'));
2874 global $sugar_config;
2875 require_once('include/utils/LogicHook.php');
2876 LogicHook::initialize();
2877 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2879 //added this check to avoid errors during install.
2880 if (empty($sugar_config['dbconfig'])) {
2881 if ($exit) exit; else return;
2884 if (!class_exists('Tracker', true)) {
2885 require_once 'modules/Trackers/Tracker.php';
2888 // Now write the cached tracker_queries
2889 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2890 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2891 $GLOBALS['current_user']->savePreferencesToDB();
2894 //check to see if this is not an `ajax call AND the user preference error flag is set
2896 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2897 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2898 && ($_REQUEST['action']!='favorites' && $_REQUEST['action']!='DynamicAction')
2899 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2900 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2903 global $app_strings;
2904 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2905 $err_mess = $app_strings['ERROR_USER_PREFS'];
2906 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2909 ajaxStatus.flashStatus('$err_mess',7000);
2915 if(class_exists('DBManagerFactory')) {
2916 $db = DBManagerFactory::getInstance();
2924 register_shutdown_function('sugar_cleanup');
2928 check_logic_hook - checks to see if your custom logic is in the logic file
2929 if not, it will add it. If the file isn't built yet, it will create the file
2932 function check_logic_hook_file($module_name, $event, $action_array){
2933 require_once('include/utils/logic_utils.php');
2936 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2938 $hook_array = get_hook_array($module_name);
2940 if(check_existing_element($hook_array, $event, $action_array)==true){
2941 //the hook at hand is present, so do nothing
2946 if(!empty($hook_array[$event]))
2948 $logic_count = count($hook_array[$event]);
2951 if($action_array[0]==""){
2952 $action_array[0] = $logic_count + 1;
2954 $hook_array[$event][] = $action_array;
2957 //end if the file exists already
2960 if($action_array[0]==""){
2961 $action_array[0] = 1;
2963 $hook_array = array();
2964 $hook_array[$event][] = $action_array;
2965 //end if else file exists already
2967 if($add_logic == true){
2969 //reorder array by element[0]
2970 //$hook_array = reorder_array($hook_array, $event);
2971 //!!!Finish this above TODO
2973 $new_contents = replace_or_add_logic_type($hook_array);
2974 write_logic_file($module_name, $new_contents);
2976 //end if add_element is true
2979 //end function check_logic_hook_file
2982 function remove_logic_hook($module_name, $event, $action_array) {
2983 require_once('include/utils/logic_utils.php');
2986 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2987 // The file exists, let's make sure the hook is there
2988 $hook_array = get_hook_array($module_name);
2990 if(check_existing_element($hook_array, $event, $action_array)==true){
2991 // The hook is there, time to take it out.
2993 foreach ( $hook_array[$event] as $i => $hook ) {
2994 // We don't do a full comparison below just in case the filename changes
2995 if ( $hook[0] == $action_array[0]
2996 && $hook[1] == $action_array[1]
2997 && $hook[3] == $action_array[3]
2998 && $hook[4] == $action_array[4] ) {
2999 unset($hook_array[$event][$i]);
3003 $new_contents = replace_or_add_logic_type($hook_array);
3004 write_logic_file($module_name, $new_contents);
3010 function display_stack_trace($textOnly=false){
3012 $stack = debug_backtrace();
3014 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
3022 foreach($stack as $item) {
3028 if(isset($item['file']))
3029 $file = $item['file'];
3030 if(isset($item['class']))
3031 $class = $item['class'];
3032 if(isset($item['line']))
3033 $line = $item['line'];
3034 if(isset($item['function']))
3035 $function = $item['function'];
3039 $out .= '<font color="black"><b>';
3045 $out .= '</b></font><font color="blue">';
3048 $out .= "[L:{$line}]";
3051 $out .= '</font><font color="red">';
3054 $out .= "({$class}:{$function})";
3057 $out .= '</font><br>';
3069 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
3070 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
3071 $halt_script = true;
3073 case 2048: return; //depricated we have lots of these ignore them
3076 if ( error_reporting() & E_NOTICE ) {
3077 $halt_script = false;
3083 case E_USER_WARNING:
3084 case E_COMPILE_WARNING:
3085 case E_CORE_WARNING:
3088 $halt_script = false;
3093 case E_COMPILE_ERROR:
3097 $type = "Fatal Error";
3102 $type = "Parse Error";
3106 //don't know what it is might not be so bad
3107 $halt_script = false;
3108 $type = "Unknown Error ($errno)";
3111 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3113 display_stack_trace();
3123 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3125 set_error_handler('StackTraceErrorHandler');
3127 function get_sub_cookies($name){
3129 if(isset($_COOKIE[$name])){
3130 $subs = explode('#', $_COOKIE[$name]);
3131 foreach($subs as $cookie){
3132 if(!empty($cookie)){
3133 $cookie = explode('=', $cookie);
3135 $cookies[$cookie[0]] = $cookie[1];
3144 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3146 if(!empty($sub_object_array)){
3148 foreach($sub_object_array as $sub_object){
3150 //run_second level is set to true if you need to remove sub-sub components
3151 if($run_second_level==true){
3153 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3155 //end if run_second_level is true
3157 $sub_object->mark_deleted($sub_object->id);
3158 //end foreach sub component
3160 //end if this is not empty
3163 //end function mark_delete_components
3167 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3169 function return_bytes($val)
3172 $last = strtolower($val{strlen($val)-1});
3176 // The 'G' modifier is available since PHP 5.1.0
3189 * Adds the href HTML tags around any URL in the $string
3191 function url2html($string) {
3193 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3194 return $return_string;
3196 // End customization by Julian
3199 * tries to determine whether the Host machine is a Windows machine
3201 function is_windows() {
3202 static $is_windows = null;
3203 if (!isset($is_windows)) {
3204 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3210 * equivalent for windows filesystem for PHP's is_writable()
3211 * @param string file Full path to the file/dir
3212 * @return bool true if writable
3214 function is_writable_windows($file) {
3215 if($file{strlen($file)-1}=='/') {
3216 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3219 // the assumption here is that Windows has an inherited permissions scheme
3220 // any file that is a descendant of an unwritable directory will inherit
3221 // that property and will trigger a failure below.
3226 $file = str_replace("/", '\\', $file);
3228 if(file_exists($file)) {
3229 if (!($f = @sugar_fopen($file, 'r+')))
3235 if(!($f = @sugar_fopen($file, 'w')))
3244 * best guesses Timezone based on webserver's TZ settings
3246 function lookupTimezone($userOffset = 0)
3248 return TimeDate::guessTimezone($userOffset);
3251 function convert_module_to_singular($module_array){
3254 foreach($module_array as $key => $value){
3255 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3257 if($value=="Cases") {
3258 $module_array[$key] = "Case";
3260 if($key=="projecttask"){
3261 $module_array['ProjectTask'] = "Project Task";
3262 unset($module_array[$key]);
3266 return $module_array;
3268 //end function convert_module_to_singular
3272 * Given the bean_name which may be plural or singular return the singular
3273 * bean_name. This is important when you need to include files.
3275 function get_singular_bean_name($bean_name){
3276 global $beanFiles, $beanList;
3277 if(array_key_exists($bean_name, $beanList)){
3278 return $beanList[$bean_name];
3286 * Given the potential module name (singular name, renamed module name)
3287 * Return the real internal module name.
3289 function get_module_from_singular($singular) {
3291 // find the internal module name for a singular name
3292 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3294 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3296 foreach ($singular_modules as $mod_name=>$sin_name) {
3297 if ($singular == $sin_name and $mod_name != $sin_name) {
3303 // find the internal module name for a renamed module
3304 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3306 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3308 foreach ($moduleList as $mod_name=>$name) {
3309 if ($singular == $name and $mod_name != $name) {
3315 // if it's not a singular name, nor a renamed name, return the original value
3319 function get_label($label_tag, $temp_module_strings){
3320 global $app_strings;
3321 if(!empty($temp_module_strings[$label_tag])){
3323 $label_name = $temp_module_strings[$label_tag];
3325 if(!empty($app_strings[$label_tag])){
3326 $label_name = $app_strings[$label_tag];
3328 $label_name = $label_tag;
3333 //end function get_label
3337 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3339 $rel_list = array();
3341 foreach($focus->relationship_fields as $rel_key => $rel_value){
3342 if($rel_value == $relationship_name){
3343 $temp_bean = get_module_info($tar_rel_module);
3344 // echo $focus->$rel_key;
3345 $temp_bean->retrieve($focus->$rel_key);
3346 if($temp_bean->id!=""){
3348 $rel_list[] = $temp_bean;
3354 foreach($focus->field_defs as $field_name => $field_def){
3355 //Check if the relationship_name matches a "relate" field
3356 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3357 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3358 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3359 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3361 $temp_bean = get_module_info($tar_rel_module);
3362 // echo $focus->$field_def['id_name'];
3363 $temp_bean->retrieve($focus->$field_def['id_name']);
3364 if($temp_bean->id!=""){
3366 $rel_list[] = $temp_bean;
3369 //Check if the relationship_name matches a "link" in a relate field
3370 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3371 $temp_bean = get_module_info($tar_rel_module);
3372 // echo $focus->$rel_value['id_name'];
3373 $temp_bean->retrieve($focus->$rel_value['id_name']);
3374 if($temp_bean->id!=""){
3376 $rel_list[] = $temp_bean;
3382 // special case for unlisted parent-type relationships
3383 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3384 $temp_bean = get_module_info($tar_rel_module);
3385 $temp_bean->retrieve($focus->parent_id);
3386 if($temp_bean->id!=""){
3387 $rel_list[] = $temp_bean;
3394 //end function search_filter_rel_info
3397 function get_module_info($module_name){
3401 //Get dictionary and focus data for module
3402 $vardef_name = $beanList[$module_name];
3404 if($vardef_name=="aCase"){
3405 $class_name = "Case";
3407 $class_name = $vardef_name;
3410 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3414 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3416 $module_bean = new $vardef_name();
3417 return $module_bean;
3418 //end function get_module_table
3422 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3424 * @param string $moduleName
3426 function get_valid_bean_name($module_name){
3429 $vardef_name = $beanList[$module_name];
3430 if($vardef_name=="aCase"){
3431 $bean_name = "Case";
3433 $bean_name = $vardef_name;
3440 function checkAuthUserStatus(){
3447 * This function returns an array of phpinfo() results that can be parsed and
3448 * used to figure out what version we run, what modules are compiled in, etc.
3449 * @param $level int info level constant (1,2,4,8...64);
3450 * @return $returnInfo array array of info about the PHP environment
3451 * @author original by "code at adspeed dot com" Fron php.net
3452 * @author customized for Sugar by Chris N.
3454 function getPhpInfo($level=-1) {
3455 /** Name (constant) Value Description
3456 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3457 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3458 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3459 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3460 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3461 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3462 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3463 INFO_ALL -1 Shows all of the above. This is the default value.
3467 $phpinfo = ob_get_contents();
3470 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3471 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3472 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3473 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3476 $returnInfo = array();
3478 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3479 $returnInfo['PHP Version'] = $version[1];
3483 for ($i=1; $i<count($parsedInfo); $i++) {
3484 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3485 $vName = trim($match[1]);
3486 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3488 foreach ($parsedInfo2 AS $vOne) {
3489 $vPat = '<info>([^<]+)<\/info>';
3490 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3491 $vPat2 = "/$vPat\s*$vPat/";
3493 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3494 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3495 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3496 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3508 * This function will take a string that has tokens like {0}, {1} and will replace
3509 * those tokens with the args provided
3510 * @param $format string to format
3511 * @param $args args to replace
3512 * @return $result a formatted string
3514 function string_format($format, $args){
3518 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3519 * IN () fails and IN ('') works.
3521 if (count($args) == 1)
3524 $singleArgument = current($args);
3525 if (empty($singleArgument))
3527 return str_replace("{0}", "''", $result);
3532 for($i = 0; $i < count($args); $i++){
3533 $result = str_replace('{'.$i.'}', $args[$i], $result);
3539 * Generate a string for displaying a unique identifier that is composed
3540 * of a system_id and number. This is use to allow us to generate quote
3541 * numbers using a DB auto-increment key from offline clients and still
3542 * have the number be unique (since it is modified by the system_id.
3544 * @param $num of bean
3545 * @param $system_id from system
3546 * @return $result a formatted string
3548 function format_number_display($num, $system_id){
3549 global $sugar_config;
3550 if(isset($num) && !empty($num)){
3551 $num=unformat_number($num);
3552 if(isset($system_id) && $system_id == 1){
3553 return sprintf("%d", $num);
3556 return sprintf("%d-%d", $num, $system_id);
3560 function checkLoginUserStatus(){
3564 * This function will take a number and system_id and format
3565 * @param $url URL containing host to append port
3566 * @param $port the port number - if '' is passed, no change to url
3567 * @return $resulturl the new URL with the port appended to the host
3569 function appendPortToHost($url, $port)
3573 // if no port, don't change the url
3576 $split = explode("/", $url);
3577 //check if it starts with http, in case they didn't include that in url
3578 if(str_begin($url, 'http'))
3580 //third index ($split[2]) will be the host
3581 $split[2] .= ":".$port;
3583 else // otherwise assumed to start with host name
3585 //first index ($split[0]) will be the host
3586 $split[0] .= ":".$port;
3589 $resulturl = implode("/", $split);
3596 * Singleton to return JSON object
3597 * @return JSON object
3599 function getJSONobj() {
3600 static $json = null;
3602 require_once('include/JSON.php');
3603 $json = new JSON(JSON_LOOSE_TYPE);
3608 require_once('include/utils/db_utils.php');
3611 * Set default php.ini settings for entry points
3613 function setPhpIniSettings() {
3615 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3617 if(function_exists('gzclose') && headers_sent() == false) {
3618 ini_set('zlib.output_compression', 1);
3622 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3624 /*if(function_exists('mb_strlen')) {
3625 ini_set('mbstring.func_overload', 7);
3626 ini_set('mbstring.internal_encoding', 'UTF-8');
3630 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3631 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3632 $backtrack_limit = ini_get('pcre.backtrack_limit');
3633 if(!empty($backtrack_limit)) {
3634 ini_set('pcre.backtrack_limit', '-1');
3639 * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
3640 * language files. Language file merges do not need to account for null values so we can get some
3641 * performance increases by using this specialized function. Note this merge function does not properly
3642 * handle null values.
3648 function sugarLangArrayMerge($gimp, $dom)
3650 if(is_array($gimp) && is_array($dom))
3652 foreach($dom as $domKey => $domVal)
3654 if(isset($gimp[$domKey]))
3656 if(is_array($domVal))
3659 foreach ( $domVal as $domArrKey => $domArrVal )
3660 $tempArr[$domArrKey] = $domArrVal;
3661 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3662 if ( !isset($tempArr[$gimpArrKey]) )
3663 $tempArr[$gimpArrKey] = $gimpArrVal;
3664 $gimp[$domKey] = $tempArr;
3668 $gimp[$domKey] = $domVal;
3673 $gimp[$domKey] = $domVal;
3677 // if the passed value for gimp isn't an array, then return the $dom
3678 elseif(is_array($dom))
3686 * like array_merge() but will handle array elements that are themselves arrays;
3687 * PHP's version just overwrites the element with the new one.
3689 * @internal Note that this function deviates from the internal array_merge()
3690 * functions in that it does does not treat numeric keys differently
3691 * than string keys. Additionally, it deviates from
3692 * array_merge_recursive() by not creating an array when like values
3695 * @param array gimp the array whose values will be overloaded
3696 * @param array dom the array whose values will pwn the gimp's
3697 * @return array beaten gimp
3699 function sugarArrayMerge($gimp, $dom) {
3700 if(is_array($gimp) && is_array($dom)) {
3701 foreach($dom as $domKey => $domVal) {
3702 if(array_key_exists($domKey, $gimp)) {
3703 if(is_array($domVal)) {
3705 foreach ( $domVal as $domArrKey => $domArrVal )
3706 $tempArr[$domArrKey] = $domArrVal;
3707 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3708 if ( !array_key_exists($gimpArrKey, $tempArr) )
3709 $tempArr[$gimpArrKey] = $gimpArrVal;
3710 $gimp[$domKey] = $tempArr;
3712 $gimp[$domKey] = $domVal;
3715 $gimp[$domKey] = $domVal;
3719 // if the passed value for gimp isn't an array, then return the $dom
3720 elseif(is_array($dom))
3727 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3729 * @param array gimp the array whose values will be overloaded
3730 * @param array dom the array whose values will pwn the gimp's
3731 * @return array beaten gimp
3733 function sugarArrayMergeRecursive($gimp, $dom) {
3734 if(is_array($gimp) && is_array($dom)) {
3735 foreach($dom as $domKey => $domVal) {
3736 if(array_key_exists($domKey, $gimp)) {
3737 if(is_array($domVal) && is_array($gimp[$domKey])) {
3738 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3740 $gimp[$domKey] = $domVal;
3743 $gimp[$domKey] = $domVal;
3747 // if the passed value for gimp isn't an array, then return the $dom
3748 elseif(is_array($dom))
3755 * finds the correctly working versions of PHP-JSON
3756 * @return bool True if NOT found or WRONG version
3758 function returnPhpJsonStatus() {
3759 if(function_exists('json_encode')) {
3760 $phpInfo = getPhpInfo(8);
3761 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3763 return true; // not found
3768 * getTrackerSubstring
3770 * Returns a [number]-char or less string for the Tracker to display in the header
3771 * based on the tracker_max_display_length setting in config.php. If not set,
3772 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3774 * @param string name field for a given Object
3775 * @return string [number]-char formatted string if length of string exceeds the max allowed
3777 function getTrackerSubstring($name) {
3778 static $max_tracker_item_length;
3781 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3782 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3784 global $sugar_config;
3786 if(!isset($max_tracker_item_length)) {
3787 if(isset($sugar_config['tracker_max_display_length'])) {
3788 $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;
3790 $max_tracker_item_length = 15;
3794 if($strlen > $max_tracker_item_length) {
3795 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length);
3802 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3803 $where_clauses= array();
3805 $table_name=$bean->object_name;
3806 foreach ($field_list[$module] as $field=>$parms) {
3807 if(isset($values[$field]) && $values[$field] != "") {
3809 if (!empty($parms['operator'])) {
3810 $operator=$parms['operator'];
3812 if (is_array($values[$field])) {
3815 foreach ($values[$field] as $key => $val) {
3816 if ($val != ' ' and $val != '') {
3817 if (!empty($field_value)) {
3820 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3824 $field_value=$GLOBALS['db']->quote($values[$field]);
3826 //set db_fields array.
3827 if (!isset($parms['db_field']) ) {
3828 $parms['db_field'] = array($field);
3830 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3831 global $current_user;
3832 $field_value = $GLOBALS['db']->quote($current_user->id);
3838 if ($field_value != '') {
3840 foreach ($parms['db_field'] as $db_field) {
3841 if (strstr($db_field,'.')===false) {
3842 $db_field=$bean->table_name.".".$db_field;
3844 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3845 $db_field='upper('.$db_field.")";
3846 $field_value=strtoupper($field_value);
3850 if (!empty($where)) {
3853 switch (strtolower($operator)) {
3855 $where .= $db_field . " like '".$field_value.$like_char."'";
3858 $where .= $db_field . " in (".$field_value.')';
3861 $where .= $db_field . " = '".$field_value ."'";
3866 if (!empty($where)) {
3868 array_push($where_clauses, '( '.$where.' )');
3870 array_push($where_clauses, $where);
3875 if ($add_custom_fields) {
3876 require_once('modules/DynamicFields/DynamicField.php');
3877 $bean->setupCustomFields($module);
3878 $bean->custom_fields->setWhereClauses($where_clauses);
3880 return $where_clauses;
3883 function add_quotes($str) {
3888 * This function will rebuild the config file
3889 * @param $sugar_config
3890 * @param $sugar_version
3891 * @return bool true if successful
3893 function rebuildConfigFile($sugar_config, $sugar_version) {
3894 // add defaults to missing values of in-memory sugar_config
3895 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3896 // need to override version with default no matter what
3897 $sugar_config['sugar_version'] = $sugar_version;
3899 ksort( $sugar_config );
3901 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3910 * getJavascriptSiteURL
3911 * This function returns a URL for the client javascript calls to access
3912 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3913 * are used to access the site. Thus, the hostname in the URL returned may
3914 * not always match that of $sugar_config['site_url']. Basically, the
3915 * assumption is that however the user accessed the website is how they
3916 * will continue to with subsequent javascript requests. If the variable
3917 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3918 * @return $site_url The url used to refer to the website
3920 function getJavascriptSiteURL() {
3921 global $sugar_config;
3922 if(!empty($_SERVER['HTTP_REFERER'])) {
3923 $url = parse_url($_SERVER['HTTP_REFERER']);
3924 $replacement_url = $url['scheme']."://".$url['host'];
3925 if(!empty($url['port']))
3926 $replacement_url .= ':'.$url['port'];
3927 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3929 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3930 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3931 $site_url = preg_replace('/^http\:/','https:',$site_url);
3934 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3938 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3939 function add_squotes($str) {
3940 return "'" . $str . "'";
3944 // recursive function to count the number of levels within an array
3945 function array_depth($array, $depth_count=-1, $depth_array=array()){
3947 if (is_array($array)){
3948 foreach ($array as $key => $value){
3949 $depth_array[] = array_depth($value, $depth_count);
3953 return $depth_count;
3955 foreach ($depth_array as $value){
3956 $depth_count = $value > $depth_count ? $value : $depth_count;
3958 return $depth_count;
3962 * Creates a new Group User
3963 * @param string $name Name of Group User
3964 * @return string GUID of new Group User
3966 function createGroupUser($name) {
3969 $group = new User();
3970 $group->user_name = $name;
3971 $group->last_name = $name;
3972 $group->is_group = 1;
3973 $group->deleted = 0;
3974 $group->status = 'Active'; // cn: bug 6711
3975 $group->setPreference('timezone', TimeDate::userTimezone());
3982 * Helper function to locate an icon file given only a name
3983 * Searches through the various paths for the file
3984 * @param string iconFileName The filename of the icon
3985 * @return string Relative pathname of the located icon, or '' if not found
3988 function _getIcon($iconFileName)
3991 $iconName = "icon_{$iconFileName}.gif";
3992 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3994 //First try un-ucfirst-ing the icon name
3995 if ( empty($iconFound) )
3996 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3997 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3999 //Next try removing the icon prefix
4000 if ( empty($iconFound) )
4001 $iconName = "{$iconFileName}.gif";
4002 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
4004 if ( empty($iconFound) )
4010 * Function to grab the correct icon image for Studio
4011 * @param string $iconFileName Name of the icon file
4012 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
4013 * @param string $width Width of image
4014 * @param string $height Height of image
4015 * @param string $align Alignment of image
4016 * @param string $alt Alt tag of image
4017 * @return string $string <img> tag with corresponding image
4020 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
4022 global $app_strings, $theme;
4024 $iconName = _getIcon($iconFileName);
4025 if(empty($iconName)){
4026 $iconName = _getIcon($altFileName);
4027 if (empty($iconName))
4029 return $app_strings['LBL_NO_IMAGE'];
4032 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4036 * Function to grab the correct icon image for Dashlets Dialog
4037 * @param string $filename Location of the icon file
4038 * @param string $module Name of the module to fall back onto if file does not exist
4039 * @param string $width Width of image
4040 * @param string $height Height of image
4041 * @param string $align Alignment of image
4042 * @param string $alt Alt tag of image
4043 * @return string $string <img> tag with corresponding image
4046 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
4047 global $app_strings, $theme;
4048 $iconName = _getIcon($module . "_32");
4049 if (empty($iconName))
4051 $iconName = _getIcon($module);
4053 if(empty($iconName)){
4054 return $app_strings['LBL_NO_IMAGE'];
4056 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4059 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
4060 function html_entity_decode_utf8($string)
4063 // replace numeric entities
4064 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
4065 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
4066 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
4067 // replace literal entities
4068 if (!isset($trans_tbl))
4070 $trans_tbl = array();
4071 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
4072 $trans_tbl[$key] = utf8_encode($val);
4074 return strtr($string, $trans_tbl);
4077 // Returns the utf string corresponding to the unicode value
4078 function code2utf($num)
4080 if ($num < 128) return chr($num);
4081 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
4082 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4083 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4087 function str_split_php4($string, $length = 1) {
4088 $string_length = strlen($string);
4091 if ($length > $string_length) {
4092 // use the string_length as the string is shorter than the length
4093 $length = $string_length;
4095 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
4096 $return[] = substr($string, $cursor, $length);
4101 if (version_compare(phpversion(), '5.0.0', '<')) {
4102 function str_split($string, $length = 1) {
4103 return str_split_php4($string, $length);
4108 * @deprecated use DBManagerFactory::isFreeTDS
4110 function is_freetds()
4112 return DBManagerFactory::isFreeTDS();
4116 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
4118 * @todo this won't work completely right until we impliment css compression and combination
4119 * for now, we'll just include the last css file found.
4121 * @return chart.css file to use
4123 function chartStyle()
4125 return SugarThemeRegistry::current()->getCSSURL('chart.css');
4129 * Chart dashlet helper functions that returns the correct XML color file for charts,
4130 * dependent on the current theme.
4132 * @return sugarColors.xml to use
4134 function chartColors()
4136 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
4137 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4138 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4140 /* End Chart Dashlet helper functions */
4143 * This function is designed to set up the php enviroment
4144 * for AJAX requests.
4147 function ajaxInit() {
4148 ini_set('display_errors', 'false');
4152 * Returns an absolute path from the given path, determining if it is relative or absolute
4154 * @param string $path
4157 function getAbsolutePath(
4159 $currentServer = false
4162 $path = trim($path);
4164 // try to match absolute paths like \\server\share, /directory or c:\
4165 if ( ( substr($path,0,2) == '\\\\' )
4166 || ( $path[0] == '/' )
4167 || preg_match('/^[A-z]:/i',$path)
4171 return getcwd().'/'.$path;
4175 * Returns the bean object of the given module
4177 * @deprecated use SugarModule::loadBean() instead
4178 * @param string $module
4185 return SugarModule::get($module)->loadBean();
4190 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4192 function isTouchScreen()
4194 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4196 // first check if we have forced use of the touch enhanced interface
4197 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4201 // next check if we should use the touch interface with our device
4202 if ( strpos($ua, 'ipad') !== false ) {
4210 * Returns the shortcut keys to access the shortcut links. Shortcut
4211 * keys vary depending on browser versions and operating systems.
4212 * @return String value of the shortcut keys
4214 function get_alt_hot_key() {
4216 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4217 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4218 $isMac = strpos($ua, 'mac') !== false;
4219 $isLinux = strpos($ua, 'linux') !== false;
4221 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4222 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4223 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4226 return $isMac ? 'Ctrl+' : 'Alt+';
4229 function can_start_session(){
4230 if(!empty($_GET['PHPSESSID'])) {
4233 $session_id = session_id();
4234 return empty($session_id) ? true : false;
4237 function load_link_class($properties){
4239 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4240 require_once($properties['link_file']);
4241 $class = $properties['link_class'];
4247 function inDeveloperMode()
4249 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4253 * Filter the protocol list for inbound email accounts.
4255 * @param array $protocol
4257 function filterInboundEmailPopSelection($protocol)
4259 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4261 if( isset($protocol['pop3']) )
4262 unset($protocol['pop3']);
4265 $protocol['pop3'] = 'POP3';
4271 * The function is used because currently we are not supporting mbstring.func_overload
4272 * 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.
4273 * 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.
4274 * @returns the substred strings.
4276 function sugar_substr($string, $length, $charset='UTF-8')
4278 if(mb_strlen($string,$charset) > $length) {
4279 $string = trim(mb_substr(trim($string),0,$length,$charset));
4285 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4286 * This will work even without setting the mbstring.*encoding
4288 function sugar_ucfirst($string, $charset='UTF-8') {
4289 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4296 function unencodeMultienum($string) {
4297 if (is_array($string))
4301 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4302 $string = substr(substr($string, 1), 0, strlen($string) -2);
4305 return explode('^,^', $string);
4308 function encodeMultienumValue($arr) {
4309 if (!is_array($arr))
4315 $string = "^" . implode('^,^', $arr) . "^";
4321 * create_export_query is used for export and massupdate
4322 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4323 * This function will correct the where clause and output necessary join condition for them
4324 * @param $module: the module name
4325 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4326 * @param $where: where clauses
4327 * @return $ret_array['where']: corrected where clause
4328 * @return $ret_array['join']: extra join condition
4330 function create_export_query_relate_link_patch($module, $searchFields, $where){
4331 if(file_exists('modules/'.$module.'/SearchForm.html')){
4332 $ret_array['where'] = $where;
4335 $seed = loadBean($module);
4336 foreach($seed->field_defs as $name=>$field)
4339 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4340 $seed->load_relationship($field['link']);
4342 if(empty($join_type))
4344 $params['join_type'] = ' LEFT JOIN ';
4348 $params['join_type'] = $join_type;
4350 if(isset($data['join_name']))
4352 $params['join_table_alias'] = $field['join_name'];
4356 $params['join_table_alias'] = 'join_'.$field['name'];
4359 if(isset($data['join_link_name']))
4361 $params['join_table_link_alias'] = $field['join_link_name'];
4365 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4367 $join = $seed->$field['link']->getJoin($params, true);
4368 $join_table_alias = 'join_'.$field['name'];
4369 if(isset($field['db_concat_fields'])){
4370 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4371 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4373 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4377 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4382 * 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.
4383 * @Depends on QuickRepairAndRebuild.php
4384 * @Relate bug 30642 ,23177
4386 function clearAllJsAndJsLangFilesWithoutOutput(){
4387 global $current_language , $mod_strings;
4388 $MBmodStrings = $mod_strings;
4389 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4390 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4391 $repair = new RepairAndClear();
4392 $repair->module_list = array();
4393 $repair->show_output = false;
4394 $repair->clearJsLangFiles();
4395 $repair->clearJsFiles();
4396 $mod_strings = $MBmodStrings;
4400 * This function will allow you to get a variable value from query string
4402 function getVariableFromQueryString($variable, $string){
4404 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4414 * should_hide_iframes
4415 * This is a helper method to determine whether or not to show iframes (My Sites) related
4416 * information in the application.
4418 * @return boolean flag indicating whether or not iframes module should be hidden
4420 function should_hide_iframes() {
4421 //Remove the MySites module
4422 if(file_exists('modules/iFrames/iFrame.php')) {
4423 if(!class_exists("iFrame")) {
4424 require_once('modules/iFrames/iFrame.php');
4432 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4434 * @param string $version
4435 * @return string RC, BETA, GA
4437 function getVersionStatus($version){
4438 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4439 return strtoupper($matches[1]);
4446 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4447 * 5.5.1RC1 then return 5.5.1
4449 * @param string $version
4452 function getMajorMinorVersion($version){
4453 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4454 $version = $matches2[1];
4455 $arr = explode('.', $version);
4456 if(count($arr) > 2){
4458 $version = substr($version, 0, 3);
4466 * Return string composed of seconds & microseconds of current time, without dots
4469 function sugar_microtime()
4471 $now = explode(' ', microtime());
4472 $unique_id = $now[1].str_replace('.', '', $now[0]);
4477 * Extract urls from a piece of text
4479 * @return array of urls found in $string
4481 function getUrls($string)
4483 $lines = explode("<br>", trim($string));
4485 foreach($lines as $line){
4486 $regex = '/http?\:\/\/[^\" ]+/i';
4487 preg_match_all($regex, $line, $matches);
4488 foreach($matches[0] as $match){
4497 * Sanitize image file from hostile content
4498 * @param string $path Image file
4499 * @param bool $jpeg Accept only JPEGs?
4501 function verify_image_file($path, $jpeg = false)
4503 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4504 $img = imagecreatefromstring(file_get_contents($path));
4508 $img_size = getimagesize($path);
4509 $filetype = $img_size['mime'];
4510 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4511 if($filetype == "image/jpeg" || $jpeg) {
4514 $image = ob_get_clean();
4515 // not writing directly because imagejpeg does not work with streams
4516 if(file_put_contents($path, $image)) {
4519 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4520 imagealphablending($img, true);
4521 imagesavealpha($img, true);
4524 $image = ob_get_clean();
4525 if(file_put_contents($path, $image)) {
4532 // check image manually
4533 $fp = fopen($path, "rb");
4534 if(!$fp) return false;
4536 // read the whole file in chunks
4538 $data .= fread($fp,8192);
4542 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",
4544 $GLOBALS['log']->fatal("Found {$m[0]} in $path, not allowing upload");
4553 * Verify uploaded image
4554 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4555 * @param string $path Image path
4556 * @param bool $jpeg_only Accept only JPEGs?
4558 function verify_uploaded_image($path, $jpeg_only = false)
4560 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4562 $supportedExtensions['png'] = 'image/png';
4565 if(!file_exists($path) || !is_file($path)) {
4569 $img_size = getimagesize($path);
4570 $filetype = $img_size['mime'];
4571 $ext = end(explode(".", $path));
4572 if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4573 !in_array($filetype, array_values($supportedExtensions))) {
4576 return verify_image_file($path, $jpeg_only);
4579 function cmp_beans($a, $b)
4581 global $sugar_web_service_order_by;
4582 //If the order_by field is not valid, return 0;
4583 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4586 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4587 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4591 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4599 function order_beans($beans, $field_name)
4601 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4602 global $sugar_web_service_order_by;
4603 $sugar_web_service_order_by = $field_name;
4604 usort($beans, "cmp_beans");
4609 * Return search like string
4610 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4611 * @param string $str string to be searched
4612 * @param string $like_char Database like character, usually '%'
4613 * @return string Returns a string to be searched in db query
4615 function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true) {
4617 // override default wildcard character
4618 if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4619 strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4620 $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4623 // add wildcard at the beginning of the search string
4624 if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4625 $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4626 if (substr($str,0,1) <> $wildcard)
4627 $str = $wildcard.$str;
4630 // add wildcard at the end of search string (default)
4631 if ($appendWildcard) {
4632 if(substr($str,-1) <> $wildcard) {
4637 return str_replace($wildcard, $like_char, $str);
4640 //check to see if custom utils exists
4641 if(file_exists('custom/include/custom_utils.php')){
4642 include_once('custom/include/custom_utils.php');
4645 //check to see if custom utils exists in Extension framework
4646 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4647 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4650 * @param $input - the input string to sanitize
4651 * @param int $quotes - use quotes
4652 * @param string $charset - the default charset
4653 * @param bool $remove - strip tags or not
4654 * @return string - the sanitized string
4656 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4658 return htmlentities($input, $quotes, $charset);
4662 * @return string - the full text search engine name
4664 function getFTSEngineType()
4666 if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
4667 foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
4675 * @param string $optionName - name of the option to be retrieved from app_list_strings
4676 * @return array - the array to be used in option element
4678 function getFTSBoostOptions($optionName)
4680 if (isset($GLOBALS['app_list_strings'][$optionName])) {
4681 return $GLOBALS['app_list_strings'][$optionName];
4689 * utf8_recursive_encode
4691 * This function walks through an Array and recursively calls utf8_encode on the
4692 * values of each of the elements.
4694 * @param $data Array of data to encode
4695 * @return utf8 encoded Array data
4697 function utf8_recursive_encode($data)
4700 foreach($data as $key=>$val) {
4701 if(is_array($val)) {
4702 $result[$key] = utf8_recursive_encode($val);
4704 $result[$key] = utf8_encode($val);
4711 * get_language_header
4713 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4714 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4716 * @return String The lang=[Current Language] markup to insert into the <html> tag
4718 function get_language_header()
4720 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4725 * get_custom_file_if_exists
4727 * This function handles the repetitive code we have where we first check if a file exists in the
4728 * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
4729 * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
4730 * otherwise it return $file
4732 * @param $file String of filename to check
4733 * @return $file String of filename including custom directory if found
4735 function get_custom_file_if_exists($file)
4737 return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4744 * This will return the URL used to redirect the user to the help documentation.
4745 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4746 * in config.php or config_override.php.
4748 * @param string $send_edition
4749 * @param string $send_version
4750 * @param string $send_lang
4751 * @param string $send_module
4752 * @param string $send_action
4753 * @param string $dev_status
4754 * @param string $send_key
4755 * @param string $send_anchor
4756 * @return string the completed help URL
4758 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4759 global $sugar_config;
4761 if (!empty($sugar_config['custom_help_url'])) {
4762 $sendUrl = $sugar_config['custom_help_url'];
4764 if (!empty($sugar_config['custom_help_base_url'])) {
4765 $baseUrl= $sugar_config['custom_help_base_url'];
4767 $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4769 $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4770 if(!empty($send_anchor)) {
4771 $sendUrl .= "&anchor=".$send_anchor;
4778 * generateETagHeader
4780 * This function generates the necessary cache headers for using ETags with dynamic content. You
4781 * simply have to generate the ETag, pass it in, and the function handles the rest.
4783 * @param string $etag ETag to use for this content.
4785 function generateETagHeader($etag){
4786 header("cache-control:");
4787 header('Expires: ');
4788 header("ETag: " . $etag);
4790 if(isset($_SERVER["HTTP_IF_NONE_MATCH"])){
4791 if($etag == $_SERVER["HTTP_IF_NONE_MATCH"]){
4793 header("Status: 304 Not Modified");
4794 header("HTTP/1.0 304 Not Modified");