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 $query .= " AND user_name LIKE '$user_name_filter%' ";
641 if (!empty($user_id)) {
642 $query .= " OR id='{$user_id}'";
644 $query = $query.' ORDER BY user_name ASC';
645 $GLOBALS['log']->debug("get_user_array query: $query");
646 $result = $db->query($query, true, "Error filling in user array: ");
648 if ($add_blank==true) {
649 // Add in a blank row
650 $temp_result[''] = '';
653 // Get the id and the name.
654 while($row = $db->fetchByAssoc($result)) {
655 if($use_real_name == true || showFullName()) {
656 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
657 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
659 $temp_result[$row['id']] = $row['user_name'];
662 $temp_result[$row['id']] = $row['user_name'];
666 $user_array = $temp_result;
669 set_register_value('user_array', $key_name, $temp_result);
679 * uses a different query to return a list of users than get_user_array()
680 * @param args string where clause entry
681 * @return array Array of Users' details that match passed criteria
683 function getUserArrayFromFullName($args, $hide_portal_users = false) {
685 $db = DBManagerFactory::getInstance();
688 if(strpos($args, " ")) {
689 $argArray = explode(" ", $args);
695 foreach($argArray as $arg) {
696 if(!empty($inClause)) {
702 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
705 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
706 if ( $hide_portal_users ) {
707 $query .= " portal_only=0 AND ";
710 $query .= " ORDER BY last_name ASC";
712 $r = $db->query($query);
714 while($a = $db->fetchByAssoc($r)) {
715 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
723 * based on user pref then system pref
725 function showFullName() {
726 global $sugar_config;
727 global $current_user;
728 static $showFullName = null;
730 if (is_null($showFullName)) {
731 $sysPref = !empty($sugar_config['use_real_names']);
732 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
734 if($userPref != null) {
735 $showFullName = ($userPref == 'on');
737 $showFullName = $sysPref;
741 return $showFullName;
744 function clean($string, $maxLength)
746 $string = substr($string, 0, $maxLength);
747 return escapeshellcmd($string);
751 * Copy the specified request variable to the member variable of the specified object.
752 * Do no copy if the member variable is already set.
753 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
754 * All Rights Reserved.
755 * Contributor(s): ______________________________________..
757 function safe_map($request_var, & $focus, $always_copy = false)
759 safe_map_named($request_var, $focus, $request_var, $always_copy);
763 * Copy the specified request variable to the member variable of the specified object.
764 * Do no copy if the member variable is already set.
765 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
766 * All Rights Reserved.
767 * Contributor(s): ______________________________________..
769 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
771 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
772 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
773 $focus->$member_var = $_REQUEST[$request_var];
778 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
780 * @param string $language specific language to load
781 * @return array lang strings
783 function return_app_list_strings_language($language)
785 global $app_list_strings;
786 global $sugar_config;
788 $cache_key = 'app_list_strings.'.$language;
790 // Check for cached value
791 $cache_entry = sugar_cache_retrieve($cache_key);
792 if(!empty($cache_entry))
797 $default_language = $sugar_config['default_language'];
798 $temp_app_list_strings = $app_list_strings;
801 if ($language != 'en_us') {
804 if ($default_language != 'en_us' && $language != $default_language) {
805 $langs[] = $default_language;
807 $langs[] = $language;
809 $app_list_strings_array = array();
811 foreach ( $langs as $lang ) {
812 $app_list_strings = array();
813 if(file_exists("include/language/$lang.lang.php")) {
814 include("include/language/$lang.lang.php");
815 $GLOBALS['log']->info("Found language file: $lang.lang.php");
817 if(file_exists("include/language/$lang.lang.override.php")) {
818 include("include/language/$lang.lang.override.php");
819 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
821 if(file_exists("include/language/$lang.lang.php.override")) {
822 include("include/language/$lang.lang.php.override");
823 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
826 $app_list_strings_array[] = $app_list_strings;
829 $app_list_strings = array();
830 foreach ( $app_list_strings_array as $app_list_strings_item ) {
831 $app_list_strings = sugarLangArrayMerge($app_list_strings, $app_list_strings_item);
834 foreach ( $langs as $lang ) {
835 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
836 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
837 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
839 if(file_exists("custom/include/language/$lang.lang.php")) {
840 include("custom/include/language/$lang.lang.php");
841 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
845 if(!isset($app_list_strings)) {
846 $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");
850 $return_value = $app_list_strings;
851 $app_list_strings = $temp_app_list_strings;
853 sugar_cache_put($cache_key, $return_value);
855 return $return_value;
859 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
860 * $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.
861 * @param file string the language that you want include,
862 * @param app_list_strings array the golbal strings
866 function _mergeCustomAppListStrings($file , $app_list_strings){
867 $app_list_strings_original = $app_list_strings;
868 unset($app_list_strings);
869 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
870 // This way, language file can add items to save specific standard codelist from being overwritten
871 $exemptDropdowns = array();
873 if(!isset($app_list_strings) || !is_array($app_list_strings)){
874 return $app_list_strings_original;
876 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
878 // FG - bug 45525 - Specific codelists must NOT be overwritten
879 $exemptDropdowns[] = "moduleList";
880 $exemptDropdowns[] = "parent_type_display";
881 $exemptDropdowns[] = "record_type_display";
882 $exemptDropdowns[] = "record_type_display_notes";
884 foreach($app_list_strings as $key=>$value)
886 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
888 unset($app_list_strings_original["$key"]);
891 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
892 return $app_list_strings;
896 * This function retrieves an application language file and returns the array of strings included.
898 * @param string $language specific language to load
899 * @return array lang strings
901 function return_application_language($language)
903 global $app_strings, $sugar_config;
905 $cache_key = 'app_strings.'.$language;
907 // Check for cached value
908 $cache_entry = sugar_cache_retrieve($cache_key);
909 if(!empty($cache_entry))
914 $temp_app_strings = $app_strings;
915 $default_language = $sugar_config['default_language'];
918 if ($language != 'en_us') {
921 if ($default_language != 'en_us' && $language != $default_language) {
922 $langs[] = $default_language;
925 $langs[] = $language;
927 $app_strings_array = array();
929 foreach ( $langs as $lang ) {
930 $app_strings = array();
931 if(file_exists("include/language/$lang.lang.php")) {
932 include("include/language/$lang.lang.php");
933 $GLOBALS['log']->info("Found language file: $lang.lang.php");
935 if(file_exists("include/language/$lang.lang.override.php")) {
936 include("include/language/$lang.lang.override.php");
937 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
939 if(file_exists("include/language/$lang.lang.php.override")) {
940 include("include/language/$lang.lang.php.override");
941 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
943 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
944 include("custom/application/Ext/Language/$lang.lang.ext.php");
945 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
947 if(file_exists("custom/include/language/$lang.lang.php")) {
948 include("custom/include/language/$lang.lang.php");
949 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
951 $app_strings_array[] = $app_strings;
954 $app_strings = array();
955 foreach ( $app_strings_array as $app_strings_item ) {
956 $app_strings = sugarLangArrayMerge($app_strings, $app_strings_item);
959 if(!isset($app_strings)) {
960 $GLOBALS['log']->fatal("Unable to load the application language strings");
964 // If we are in debug mode for translating, turn on the prefix now!
965 if($sugar_config['translation_string_prefix']) {
966 foreach($app_strings as $entry_key=>$entry_value) {
967 $app_strings[$entry_key] = $language.' '.$entry_value;
970 if(isset($_SESSION['show_deleted'])) {
971 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
972 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
973 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
974 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
977 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
979 $return_value = $app_strings;
980 $app_strings = $temp_app_strings;
982 sugar_cache_put($cache_key, $return_value);
984 return $return_value;
988 * This function retrieves a module's language file and returns the array of strings included.
990 * @param string $language specific language to load
991 * @param string $module module name to load strings for
992 * @param bool $refresh optional, true if you want to rebuild the language strings
993 * @return array lang strings
995 function return_module_language($language, $module, $refresh=false)
998 global $sugar_config;
999 global $currentModule;
1001 // Jenny - Bug 8119: Need to check if $module is not empty
1002 if (empty($module)) {
1003 $stack = debug_backtrace();
1004 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
1010 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1011 // Check for cached value
1012 $cache_entry = sugar_cache_retrieve($cache_key);
1013 if(!empty($cache_entry))
1015 return $cache_entry;
1018 // Store the current mod strings for later
1019 $temp_mod_strings = $mod_strings;
1020 $loaded_mod_strings = array();
1021 $language_used = $language;
1022 $default_language = $sugar_config['default_language'];
1024 if(empty($language)) {
1025 $language = $default_language;
1028 // Bug 21559 - So we can get all the strings defined in the template, refresh
1029 // the vardefs file if the cached language file doesn't exist.
1030 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1031 && !empty($GLOBALS['beanList'][$module])){
1032 $object = BeanFactory::getObjectName($module);
1033 VardefManager::refreshVardefs($module,$object);
1036 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1038 // cn: bug 6048 - merge en_us with requested language
1039 if($language != $sugar_config['default_language'])
1040 $loaded_mod_strings = sugarLangArrayMerge(
1041 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1045 // Load in en_us strings by default
1046 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1047 $loaded_mod_strings = sugarLangArrayMerge(
1048 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1052 // If we are in debug mode for translating, turn on the prefix now!
1053 if($sugar_config['translation_string_prefix']) {
1054 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1055 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1059 $return_value = $loaded_mod_strings;
1060 if(!isset($mod_strings)){
1061 $mod_strings = $return_value;
1064 $mod_strings = $temp_mod_strings;
1066 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1067 sugar_cache_put($cache_key, $return_value);
1068 return $return_value;
1072 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1073 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1074 * All Rights Reserved.
1075 * Contributor(s): ______________________________________..
1076 * If you are using the current language, do not call this function unless you are loading it for the first time */
1077 function return_mod_list_strings_language($language,$module) {
1078 global $mod_list_strings;
1079 global $sugar_config;
1080 global $currentModule;
1082 $cache_key = "mod_list_str_lang.".$language.$module;
1084 // Check for cached value
1085 $cache_entry = sugar_cache_retrieve($cache_key);
1086 if(!empty($cache_entry))
1088 return $cache_entry;
1091 $language_used = $language;
1092 $temp_mod_list_strings = $mod_list_strings;
1093 $default_language = $sugar_config['default_language'];
1095 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1096 return $mod_list_strings;
1099 // cn: bug 6351 - include en_us if file langpack not available
1100 // cn: bug 6048 - merge en_us with requested language
1101 include("modules/$module/language/en_us.lang.php");
1102 $en_mod_list_strings = array();
1103 if($language_used != $default_language)
1104 $en_mod_list_strings = $mod_list_strings;
1106 if(file_exists("modules/$module/language/$language.lang.php")) {
1107 include("modules/$module/language/$language.lang.php");
1110 if(file_exists("modules/$module/language/$language.lang.override.php")){
1111 include("modules/$module/language/$language.lang.override.php");
1114 if(file_exists("modules/$module/language/$language.lang.php.override")){
1115 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1116 include("modules/$module/language/$language.lang.php.override");
1119 // cn: bug 6048 - merge en_us with requested language
1120 $mod_list_strings = sugarLangArrayMerge($en_mod_list_strings, $mod_list_strings);
1122 // if we still don't have a language pack, then log an error
1123 if(!isset($mod_list_strings)) {
1124 $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})");
1128 $return_value = $mod_list_strings;
1129 $mod_list_strings = $temp_mod_list_strings;
1131 sugar_cache_put($cache_key, $return_value);
1132 return $return_value;
1136 /** This function retrieves a theme's language file and returns the array of strings included.
1137 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1138 * All Rights Reserved.
1139 * Contributor(s): ______________________________________..
1141 function return_theme_language($language, $theme)
1143 global $mod_strings, $sugar_config, $current_language;
1145 $language_used = $language;
1146 $default_language = $sugar_config['default_language'];
1148 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1149 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1150 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1152 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1153 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";
1154 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1156 if(!isset($theme_strings))
1158 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1159 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1160 $language_used = $default_language;
1163 if(!isset($theme_strings))
1165 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1169 // If we are in debug mode for translating, turn on the prefix now!
1170 if($sugar_config['translation_string_prefix'])
1172 foreach($theme_strings as $entry_key=>$entry_value)
1174 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1178 return $theme_strings;
1183 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1184 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1185 * All Rights Reserved.
1186 * Contributor(s): ______________________________________..
1188 function return_session_value_or_default($varname, $default)
1190 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1192 return $_SESSION[$varname];
1199 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1200 * 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.
1201 * @param &$where_clauses - The array to append the clause to
1202 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1203 * @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.
1204 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1205 * All Rights Reserved.
1206 * Contributor(s): ______________________________________..
1208 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1210 if($SQL_name == null)
1212 $SQL_name = $variable_name;
1215 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1217 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1222 * Generate the appropriate SQL based on the where clauses.
1223 * @param $where_clauses - An Array of individual where clauses stored as strings
1224 * @returns string where_clause - The final SQL where clause to be executed.
1225 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1226 * All Rights Reserved.
1227 * Contributor(s): ______________________________________..
1229 function generate_where_statement($where_clauses)
1232 foreach($where_clauses as $clause)
1239 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1244 * determines if a passed string matches the criteria for a Sugar GUID
1245 * @param string $guid
1246 * @return bool False on failure
1248 function is_guid($guid) {
1249 if(strlen($guid) != 36) {
1253 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1262 * A temporary method of generating GUIDs of the correct format for our DB.
1263 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1265 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1266 * All Rights Reserved.
1267 * Contributor(s): ______________________________________..
1269 function create_guid()
1271 $microTime = microtime();
1272 list($a_dec, $a_sec) = explode(" ", $microTime);
1274 $dec_hex = dechex($a_dec* 1000000);
1275 $sec_hex = dechex($a_sec);
1277 ensure_length($dec_hex, 5);
1278 ensure_length($sec_hex, 6);
1282 $guid .= create_guid_section(3);
1284 $guid .= create_guid_section(4);
1286 $guid .= create_guid_section(4);
1288 $guid .= create_guid_section(4);
1291 $guid .= create_guid_section(6);
1297 function create_guid_section($characters)
1300 for($i=0; $i<$characters; $i++)
1302 $return .= dechex(mt_rand(0,15));
1307 function ensure_length(&$string, $length)
1309 $strlen = strlen($string);
1310 if($strlen < $length)
1312 $string = str_pad($string,$length,"0");
1314 else if($strlen > $length)
1316 $string = substr($string, 0, $length);
1320 function microtime_diff($a, $b) {
1321 list($a_dec, $a_sec) = explode(" ", $a);
1322 list($b_dec, $b_sec) = explode(" ", $b);
1323 return $b_sec - $a_sec + $b_dec - $a_dec;
1326 // check if Studio is displayed.
1327 function displayStudioForCurrentUser()
1329 global $current_user;
1330 if ( $current_user->isAdmin() ) {
1340 function displayWorkflowForCurrentUser()
1342 $_SESSION['display_workflow_for_user'] = false;
1346 // return an array with all modules where the user is an admin.
1347 function get_admin_modules_for_user($user) {
1348 $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");
1355 return($user->getDeveloperModules());
1359 function get_workflow_admin_modules_for_user($user){
1360 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1361 return $_SESSION['get_workflow_admin_modules_for_user'];
1365 $workflow_mod_list = array();
1366 foreach($moduleList as $module){
1367 $workflow_mod_list[$module] = $module;
1370 // This list is taken from teh previous version of workflow_utils.php
1371 $workflow_mod_list['Tasks'] = "Tasks";
1372 $workflow_mod_list['Calls'] = "Calls";
1373 $workflow_mod_list['Meetings'] = "Meetings";
1374 $workflow_mod_list['Notes'] = "Notes";
1375 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1376 $workflow_mod_list['Leads'] = "Leads";
1377 $workflow_mod_list['Opportunities'] = "Opportunities";
1380 $workflow_admin_modules = array();
1382 return $workflow_admin_modules;
1384 $actions = ACLAction::getUserActions($user->id);
1385 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1386 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1387 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1388 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1390 foreach ($workflow_mod_list as $key=>$val) {
1391 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1392 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1393 ($user->isDeveloperForModule($key))) {
1394 $workflow_admin_modules[$key] = $val;
1397 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1398 return ($workflow_admin_modules);
1401 // Check if user is admin for at least one module.
1402 function is_admin_for_any_module($user) {
1406 if($user->isAdmin()) {
1413 // Check if user is admin for a specific module.
1414 function is_admin_for_module($user,$module) {
1415 if (!isset($user)) {
1418 if ($user->isAdmin()) {
1426 * Check if user id belongs to a system admin.
1427 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1428 * All Rights Reserved.
1429 * Contributor(s): ______________________________________..
1431 function is_admin($user) {
1436 return $user->isAdmin();
1440 * Return the display name for a theme if it exists.
1441 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1442 * All Rights Reserved.
1443 * Contributor(s): ______________________________________..
1445 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1447 function get_theme_display($theme)
1449 return SugarThemeRegistry::get($theme)->name;
1453 * Return an array of directory names.
1454 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1455 * All Rights Reserved.
1456 * Contributor(s): ______________________________________..
1458 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1460 function get_themes()
1462 return SugarThemeRegistry::availableThemes();
1466 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1467 * Create HTML to display select options in a dropdown list. To be used inside
1468 * of a select statement in a form.
1469 * param $option_list - the array of strings to that contains the option list
1470 * param $selected - the string which contains the default value
1471 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1472 * All Rights Reserved.
1473 * Contributor(s): ______________________________________..
1475 function get_select_options ($option_list, $selected) {
1476 return get_select_options_with_id($option_list, $selected);
1480 * Create HTML to display select options in a dropdown list. To be used inside
1481 * 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.
1482 * param $option_list - the array of strings to that contains the option list
1483 * param $selected - the string which contains the default value
1484 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1485 * All Rights Reserved.
1486 * Contributor(s): ______________________________________..
1488 function get_select_options_with_id ($option_list, $selected_key) {
1489 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1494 * Create HTML to display select options in a dropdown list. To be used inside
1495 * of a select statement in a form. This method expects the option list to have keys and values. The keys are the ids. The values are the display strings.
1496 * param $label_list - the array of strings to that contains the option list
1497 * param $key_list - the array of strings to that contains the values list
1498 * param $selected - the string which contains the default value
1499 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1500 * All Rights Reserved.
1501 * Contributor(s): ______________________________________..
1503 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1504 global $app_strings;
1505 $select_options = "";
1507 //for setting null selection values to human readable --None--
1508 $pattern = "/'0?'></";
1509 $replacement = "''>".$app_strings['LBL_NONE']."<";
1511 $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
1514 if (empty($key_list)) $key_list = array();
1515 //create the type dropdown domain and set the selected value if $opp value already exists
1516 foreach ($key_list as $option_key=>$option_value) {
1518 $selected_string = '';
1519 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1520 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1521 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1523 $selected_string = 'selected ';
1526 $html_value = $option_key;
1528 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1530 $select_options = preg_replace($pattern, $replacement, $select_options);
1531 return $select_options;
1536 * Call this method instead of die().
1537 * Then we call the die method with the error message that is passed in.
1539 function sugar_die($error_message)
1543 die($error_message);
1548 * Create javascript to clear values of all elements in a form.
1549 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1550 * All Rights Reserved.
1551 * Contributor(s): ______________________________________..
1553 function get_clear_form_js () {
1554 $the_script = <<<EOQ
1555 <script type="text/javascript" language="JavaScript">
1556 function clear_form(form) {
1557 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1558 if(typeof(form.advanced) != 'undefined'){
1559 newLoc += '&advanced=' + form.advanced.value;
1561 document.location.href= newLoc;
1570 * Create javascript to set the cursor focus to specific field in a form
1571 * when the screen is rendered. The field name is currently hardcoded into the
1573 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1574 * All Rights Reserved.
1575 * Contributor(s): ______________________________________..
1577 function get_set_focus_js () {
1578 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1579 $the_script = <<<EOQ
1580 <script type="text/javascript" language="JavaScript">
1582 function set_focus() {
1583 if (document.forms.length > 0) {
1584 for (i = 0; i < document.forms.length; i++) {
1585 for (j = 0; j < document.forms[i].elements.length; j++) {
1586 var field = document.forms[i].elements[j];
1587 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1588 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1590 if (field.type == "text") {
1607 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1608 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1609 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1610 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1611 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1612 * the first - so the array is sorted by the last given column first, then the one before ...
1613 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1614 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1615 * All Rights Reserved.
1616 * Contributor(s): ______________________________________..
1618 function array_csort() {
1619 $args = func_get_args();
1620 $marray = array_shift($args);
1623 $msortline = "return(array_multisort(";
1624 foreach ($args as $arg) {
1626 if (is_string($arg)) {
1627 foreach ($marray as $row) {
1628 $sortarr[$i][] = $row[$arg];
1631 $sortarr[$i] = $arg;
1633 $msortline .= "\$sortarr[".$i."],";
1635 $msortline .= "\$marray));";
1642 * Converts localized date format string to jscalendar format
1643 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1644 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1645 * All Rights Reserved.
1646 * Contributor(s): ______________________________________..
1648 function parse_calendardate($local_format) {
1649 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1650 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1651 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1658 function translate($string, $mod='', $selectedValue=''){
1659 //$test_start = microtime();
1660 //static $mod_strings_results = array();
1662 global $current_language;
1664 if(isset($_REQUEST['login_language'])){
1665 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1667 $mod_strings = return_module_language($current_language, $mod);
1670 global $mod_strings;
1674 global $app_strings, $app_list_strings;
1676 if(isset($mod_strings[$string]))
1677 $returnValue = $mod_strings[$string];
1678 else if(isset($app_strings[$string]))
1679 $returnValue = $app_strings[$string];
1680 else if(isset($app_list_strings[$string]))
1681 $returnValue = $app_list_strings[$string];
1682 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1683 $returnValue = $app_list_strings['moduleList'][$string];
1686 //$test_end = microtime();
1688 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1690 // echo("translate results:");
1692 // $total_strings = 0;
1693 // foreach($mod_strings_results as $key=>$value)
1695 // echo("Module $key \t\t time $value \t\t<br>");
1696 // $total_time += $value;
1699 // echo("Total time: $total_time<br>");
1703 if(empty($returnValue)){
1707 if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1708 return $returnValue[$selectedValue];
1711 return $returnValue;
1714 function unTranslateNum($num) {
1716 static $num_grp_sep;
1717 global $current_user, $sugar_config;
1719 if($dec_sep == null) {
1720 $user_dec_sep = $current_user->getPreference('dec_sep');
1721 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1723 if($num_grp_sep == null) {
1724 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1725 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1728 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1729 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1734 function add_http($url) {
1735 if(!preg_match("@://@i", $url)) {
1737 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1741 return "{$scheme}://{$url}";
1748 * returns a default array of XSS tags to clean
1751 function getDefaultXssTags() {
1753 "applet" => "applet",
1758 "frameset" => "frameset",
1759 "iframe" => "iframe",
1760 "import" => "\?import",
1763 "object" => "object",
1764 "script" => "script",
1768 $ret = base64_encode(serialize($tmp));
1774 * Remove potential xss vectors from strings
1775 * @param string str String to search for XSS attack vectors
1779 function remove_xss($str)
1781 return SugarCleaner::cleanHtml($str, false);
1785 * Detects typical XSS attack patterns
1787 * @param string str String to search for XSS attack vectors
1788 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1789 * @return array Array of matches, empty on clean string
1791 function clean_xss($str, $cleanImg=true) {
1792 global $sugar_config;
1794 if(empty($sugar_config['email_xss']))
1795 $sugar_config['email_xss'] = getDefaultXssTags();
1797 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1799 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1800 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1801 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1802 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1804 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1805 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1806 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1807 $css_url = '#url\(.*\.\w+\)#';
1809 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1811 $tagmatches = array();
1813 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1814 foreach($tagmatches[1] as $no => $tag) {
1815 if(in_array($tag, $xsstags)) {
1816 // dangerous tag - take out whole
1817 $matches[] = $tagmatches[0][$no];
1820 $attrmatch = array();
1821 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1822 if(!empty($attrmatch[0])) {
1823 $matches = array_merge($matches, $attrmatch[0]);
1827 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1830 $matches = array_merge($matches,
1831 xss_check_pattern($imgsrc_regex, $str)
1835 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1836 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1838 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1839 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1840 // normalize whitelist
1841 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1842 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1845 foreach($cssUrlMatches[0] as $match) {
1846 $domain = strtolower(substr(strstr($match, "://"), 3));
1847 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1849 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1850 $matches[] = $match;
1855 $matches = array_merge($matches, $cssUrlMatches[0]);
1862 * Helper function used by clean_xss() to parse for known-bad vectors
1863 * @param string pattern Regex pattern to use
1864 * @param string str String to parse for badness
1867 function xss_check_pattern($pattern, $str) {
1868 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1873 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1875 * @param string $str
1876 * @param string $filter which corresponds to a regular expression to use; choices are:
1877 * "STANDARD" ( default )
1887 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1889 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1891 global $sugar_config;
1894 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1895 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1896 "FILE" => '#[^A-Z0-9\-_\.]#i',
1897 "NUMBER" => '#[^0-9\-]#i',
1898 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1899 "PATH_NO_URL" => '#://#i',
1900 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1901 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1902 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1903 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1906 if (preg_match($filters[$filter], $str)) {
1907 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1908 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1910 if ( $dieOnBadData ) {
1911 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1920 function clean_special_arguments() {
1921 if(isset($_SERVER['PHP_SELF'])) {
1922 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1924 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1925 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1926 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1927 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1928 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1929 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1930 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1931 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1932 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1933 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1934 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1935 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1936 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1937 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1938 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1939 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1940 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1941 clean_superglobals('offset', 'ALPHANUM');
1942 clean_superglobals('return_action');
1943 clean_superglobals('return_module');
1948 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1950 function clean_superglobals($key, $filter = 'STANDARD') {
1951 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1952 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1953 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1956 function set_superglobals($key, $val){
1958 $_POST[$key] = $val;
1959 $_REQUEST[$key] = $val;
1962 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1963 function clean_incoming_data() {
1964 global $sugar_config;
1965 global $RAW_REQUEST;
1967 if(get_magic_quotes_gpc()) {
1968 // magic quotes screw up data, we'd have to clean up
1969 $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1971 $RAW_REQUEST = $_REQUEST;
1974 if (get_magic_quotes_gpc() == 1) {
1975 $req = array_map("preprocess_param", $_REQUEST);
1976 $post = array_map("preprocess_param", $_POST);
1977 $get = array_map("preprocess_param", $_GET);
1980 $req = array_map("securexss", $_REQUEST);
1981 $post = array_map("securexss", $_POST);
1982 $get = array_map("securexss", $_GET);
1985 // PHP cannot stomp out superglobals reliably
1986 foreach($post as $k => $v) { $_POST[$k] = $v; }
1987 foreach($get as $k => $v) { $_GET[$k] = $v; }
1988 foreach($req as $k => $v) {
1990 //ensure the keys are safe as well
1993 // Any additional variables that need to be cleaned should be added here
1994 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1995 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1996 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1997 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1998 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1999 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
2000 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
2001 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
2002 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
2003 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
2004 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
2005 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
2006 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
2008 if(isset($_REQUEST['lvso'])){
2009 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
2011 // Clean "offset" and "order_by" parameters in URL
2012 foreach ($_REQUEST as $key => $val) {
2013 if (str_end($key, "_offset")) {
2014 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
2015 set_superglobals($key, $_REQUEST[$key]);
2017 elseif (str_end($key, "_ORDER_BY")) {
2018 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2019 set_superglobals($key, $_REQUEST[$key]);
2027 // Returns TRUE if $str begins with $begin
2028 function str_begin($str, $begin) {
2029 return (substr($str, 0, strlen($begin)) == $begin);
2032 // Returns TRUE if $str ends with $end
2033 function str_end($str, $end) {
2034 return (substr($str, strlen($str) - strlen($end)) == $end);
2037 function securexss($value) {
2038 if(is_array($value)){
2040 foreach($value as $key=>$val){
2041 $new[$key] = securexss($val);
2045 static $xss_cleanup= array(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2046 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2047 $value = preg_replace('/javascript:/i', 'java script:', $value);
2048 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2051 function securexsskey($value, $die=true){
2052 global $sugar_config;
2054 preg_match('/[\'"<>]/', $value, $matches);
2055 if(!empty($matches)){
2057 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2059 unset($_REQUEST[$value]);
2060 unset($_POST[$value]);
2061 unset($_GET[$value]);
2066 function preprocess_param($value){
2067 if(is_string($value)){
2068 if(get_magic_quotes_gpc() == 1){
2069 $value = stripslashes($value);
2072 $value = securexss($value);
2078 function cleanup_slashes($value)
2080 if(is_string($value)) return stripslashes($value);
2085 function set_register_value($category, $name, $value){
2086 return sugar_cache_put("{$category}:{$name}", $value);
2089 function get_register_value($category,$name){
2090 return sugar_cache_retrieve("{$category}:{$name}");
2093 function clear_register_value($category,$name){
2094 return sugar_cache_clear("{$category}:{$name}");
2096 // this function cleans id's when being imported
2097 function convert_id($string)
2099 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2101 // single quotes are essential here,
2102 // or alternative escape all $ as \$
2104 'return ord($matches[0]);'
2109 * @deprecated use SugarTheme::getImage()
2111 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2113 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2116 * @deprecated use SugarTheme::getImageURL()
2118 function getImagePath($image_name)
2120 return SugarThemeRegistry::current()->getImageURL($image_name);
2123 function getWebPath($relative_path){
2124 //if it has a :// then it isn't a relative path
2125 if(substr_count($relative_path, '://') > 0) return $relative_path;
2126 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2127 return $relative_path;
2130 function getVersionedPath($path, $additional_attrs='')
2132 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2133 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2134 if(inDeveloperMode()) {
2136 if(empty($rand)) $rand = mt_rand();
2141 if(is_array($additional_attrs)) {
2142 $additional_attrs = join("|",$additional_attrs);
2144 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2145 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2146 // remove / - it confuses some parsers
2147 $str = strtr($str, '/+', '-_');
2148 if(empty($path)) return $str;
2150 return $path . "?v=$str";
2153 function getVersionedScript($path, $additional_attrs='')
2155 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2158 function getJSPath($relative_path, $additional_attrs='')
2160 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2161 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2164 function getSWFPath($relative_path, $additional_params=''){
2165 $path = $relative_path;
2166 if (!empty($additional_params)){
2167 $path .= '?' . $additional_params;
2169 if (defined('TEMPLATE_URL')){
2170 $path = TEMPLATE_URL . '/' . $path;
2179 function getSQLDate($date_str)
2181 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2183 if ( strlen($match[2]) == 1)
2185 $match[2] = "0".$match[2];
2187 if ( strlen($match[1]) == 1)
2189 $match[1] = "0".$match[1];
2191 return "{$match[3]}-{$match[1]}-{$match[2]}";
2193 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2195 if ( strlen($match[2]) == 1)
2197 $match[2] = "0".$match[2];
2199 if ( strlen($match[1]) == 1)
2201 $match[1] = "0".$match[1];
2203 return "{$match[3]}-{$match[1]}-{$match[2]}";
2211 function clone_history(&$db, $from_id,$to_id, $to_type)
2216 require_once('include/upload_file.php');
2217 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2219 $location=array('Email'=>"modules/Emails/Email.php",
2220 'Call'=>"modules/Calls/Call.php",
2221 'Meeting'=>"modules/Meetings/Meeting.php",
2222 'Note'=>"modules/Notes/Note.php",
2223 'Tasks'=>"modules/Tasks/Task.php",
2227 foreach($tables as $table=>$bean_class)
2230 if (!class_exists($bean_class))
2232 require_once($location[$bean_class]);
2235 $bProcessingNotes=false;
2236 if ($table=='notes')
2238 $bProcessingNotes=true;
2240 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2241 $results = $db->query($query);
2242 while($row = $db->fetchByAssoc($results))
2244 //retrieve existing record.
2245 $bean= new $bean_class();
2246 $bean->retrieve($row['id']);
2247 //process for new instance.
2248 if ($bProcessingNotes)
2250 $old_note_id=$row['id'];
2251 $old_filename=$bean->filename;
2254 $bean->parent_id=$to_id;
2255 $bean->parent_type=$to_type;
2256 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2258 $bean->contact_id=$to_id;
2260 $bean->update_date_modified = false;
2261 $bean->update_modified_by = false;
2262 if(isset($bean->date_modified))
2263 $bean->date_modified = $timedate->to_db($bean->date_modified);
2264 if(isset($bean->date_entered))
2265 $bean->date_entered = $timedate->to_db($bean->date_entered);
2267 $new_id=$bean->save();
2269 //duplicate the file now. for notes.
2270 if ($bProcessingNotes && !empty($old_filename))
2272 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2274 //reset the values needed for attachment duplication.
2281 function values_to_keys($array)
2283 $new_array = array();
2284 if(!is_array($array))
2288 foreach($array as $arr){
2289 $new_array[$arr] = $arr;
2294 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2296 foreach($tables as $table)
2299 if ($table == 'emails_beans') {
2300 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2302 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2304 $results = $db->query($query);
2305 while($row = $db->fetchByAssoc($results))
2307 $query = "INSERT INTO $table ";
2310 $row[$from_column] = $to_id;
2311 $row['id'] = create_guid();
2312 if ($table=='emails_beans') {
2313 $row['bean_module'] =='Contacts';
2316 foreach($row as $name=>$value)
2322 $values .= "'$value'";
2325 $names .= ', '. $name;
2326 $values .= ", '$value'";
2329 $query .= "($names) VALUES ($values)";
2335 function get_unlinked_email_query($type, $bean) {
2336 global $current_user;
2338 $return_array['select']='SELECT emails.id ';
2339 $return_array['from']='FROM emails ';
2340 $return_array['where']="";
2341 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2343 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2344 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2345 where eear.deleted=0 and eear.email_id not in
2346 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2347 ) derivedemails on derivedemails.email_id = emails.id";
2348 $return_array['join_tables'][0] = '';
2350 if (isset($type) and !empty($type['return_as_array'])) {
2351 return $return_array;
2354 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2357 function get_emails_by_assign_or_link($params)
2359 $relation = $params['link'];
2360 $bean = $GLOBALS['app']->controller->bean;
2361 if(empty($bean->$relation)) {
2362 $bean->load_relationship($relation);
2364 if(empty($bean->$relation)) {
2365 $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
2368 $rel_module = $bean->$relation->getRelatedModuleName();
2369 $rel_join = $bean->$relation->getJoin(array(
2370 'join_table_alias' => 'link_bean',
2371 'join_table_link_alias' => 'linkt',
2373 $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
2374 $return_array['select']='SELECT emails.id ';
2375 $return_array['from'] = "FROM emails ";
2376 $return_array['join'] = " INNER JOIN (".
2377 // directly assigned emails
2378 "select eb.email_id FROM emails_beans eb where eb.bean_module = '{$bean->module_dir}' AND eb.bean_id = '{$bean->id}' AND eb.deleted=0 ".
2380 // Assigned to contacts
2381 "select DISTINCT eb.email_id FROM emails_beans eb
2382 $rel_join AND link_bean.id = eb.bean_id
2383 where eb.bean_module = '$rel_module' AND eb.deleted=0".
2385 // Related by directly by email
2386 "select DISTINCT eear.email_id from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2387 ON eabr.bean_id ='{$bean->id}' AND eabr.bean_module = '{$bean->module_dir}' AND
2388 eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0".
2390 // Related by email to linked contact
2391 "select DISTINCT eear.email_id FROM emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2392 ON eabr.email_address_id=eear.email_address_id AND eabr.bean_module = '$rel_module' AND eabr.deleted=0
2393 $rel_join AND link_bean.id = eabr.bean_id
2394 where eear.deleted=0".
2395 ") email_ids ON emails.id=email_ids.email_id ";
2396 $return_array['where']=" WHERE emails.deleted=0 ";
2398 //$return_array['join'] = '';
2399 $return_array['join_tables'][0] = '';
2401 if(0 && $bean->object_name == "Case" && !empty($bean->case_number)) {
2402 $where = str_replace("%1", $bean->case_number, $bean->getEmailSubjectMacro());
2403 $return_array["where"] .= "\n AND emails.name LIKE '%$where%'";
2406 return $return_array;
2410 * Check to see if the number is empty or non-zero
2414 function number_empty($value)
2416 return empty($value) && $value != '0';
2419 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2422 require_once($beanFiles[$bean_name]);
2423 $focus = new $bean_name();
2424 $user_array = array();
2426 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2427 $user_array = get_register_value('select_array', $key );
2431 $db = DBManagerFactory::getInstance();
2433 $temp_result = Array();
2434 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2438 $query .= $where." AND ";
2441 $query .= " {$focus->table_name}.deleted=0";
2443 if ( $order_by != '')
2445 $query .= " order by {$focus->table_name}.{$order_by}";
2448 $GLOBALS['log']->debug("get_user_array query: $query");
2449 $result = $db->query($query, true, "Error filling in user array: ");
2451 if ($add_blank==true){
2452 // Add in a blank row
2453 if($blank_is_none == true) { // set 'blank row' to "--None--"
2454 global $app_strings;
2455 $temp_result[''] = $app_strings['LBL_NONE'];
2457 $temp_result[''] = '';
2461 // Get the id and the name.
2462 while($row = $db->fetchByAssoc($result))
2464 $temp_result[$row['id']] = $row['display'];
2467 $user_array = $temp_result;
2468 set_register_value('select_array', $key ,$temp_result);
2477 * @param unknown_type $listArray
2479 // function parse_list_modules
2480 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2481 function parse_list_modules(&$listArray)
2483 global $modListHeader;
2484 $returnArray = array();
2486 foreach($listArray as $optionName => $optionVal)
2488 if(array_key_exists($optionName, $modListHeader))
2490 $returnArray[$optionName] = $optionVal;
2493 // special case for projects
2494 if(array_key_exists('Project', $modListHeader))
2496 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2499 $acldenied = ACLController::disabledModuleList($listArray,false);
2500 foreach($acldenied as $denied){
2501 unset($returnArray[$denied]);
2503 asort($returnArray);
2505 return $returnArray;
2508 function display_notice($msg = false){
2509 global $error_notice;
2510 //no error notice - lets just display the error to the user
2511 if(!isset($error_notice)){
2512 echo '<br>'.$msg . '<br>';
2514 $error_notice .= $msg . '<br>';
2518 /* checks if it is a number that at least has the plus at the beginning.
2520 function skype_formatted($number){
2521 //kbrill - BUG #15375
2522 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2525 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2527 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2530 function format_skype($number) {
2531 return preg_replace('/[^\+0-9]/','',$number);
2534 function insert_charset_header() {
2535 header('Content-Type: text/html; charset=UTF-8');
2538 function getCurrentURL()
2541 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2546 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2550 function javascript_escape($str) {
2553 for($i = 0; $i < strlen($str); $i++) {
2555 if(ord(substr($str, $i, 1))==10){
2557 }elseif(ord(substr($str, $i, 1))==13){
2561 $new_str .= $str{$i};
2565 $new_str = str_replace("'", "\\'", $new_str);
2570 function js_escape($str, $keep=true){
2571 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2574 $str = javascript_escape($str);
2577 $str = str_replace("'", " ", $str);
2578 $str = str_replace('"', " ", $str);
2583 //end function js_escape
2586 function br2nl($str) {
2587 $regex = "#<[^>]+br.+?>#i";
2588 preg_match_all($regex, $str, $matches);
2590 foreach($matches[0] as $match) {
2591 $str = str_replace($match, "<br>", $str);
2594 $brs = array('<br>','<br/>', '<br />');
2595 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2596 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2597 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2598 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2604 * Private helper function for displaying the contents of a given variable.
2605 * This function is only intended to be used for SugarCRM internal development.
2606 * The ppd stands for Pre Print Die.
2608 function _ppd($mixed)
2614 * Private helper function for displaying the contents of a given variable in
2615 * the Logger. This function is only intended to be used for SugarCRM internal
2616 * development. The pp stands for Pre Print.
2617 * @param $mixed var to print_r()
2618 * @param $die boolean end script flow
2619 * @param $displayStackTrace also show stack trace
2621 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2622 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2624 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2628 $mix = print_r($mixed, true); // send print_r() output to $mix
2629 $stack = debug_backtrace();
2631 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2632 $GLOBALS['log']->$loglevel($mix);
2633 if($displayStackTrace) {
2634 foreach($stack as $position) {
2635 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2639 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2640 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2648 * private helper function to quickly show the major, direct, field attributes of a given bean.
2649 * The ppf stands for Pre[formatted] Print Focus [object]
2650 * @param object bean The focus bean
2652 function _ppf($bean, $die=false) {
2658 * Private helper function for displaying the contents of a given variable.
2659 * This function is only intended to be used for SugarCRM internal development.
2660 * The pp stands for Pre Print.
2662 function _pp($mixed)
2667 * Private helper function for displaying the contents of a given variable.
2668 * This function is only intended to be used for SugarCRM internal development.
2669 * The pp stands for Pre Print.
2671 function _pstack_trace($mixed=NULL)
2676 * Private helper function for displaying the contents of a given variable.
2677 * This function is only intended to be used for SugarCRM internal development.
2678 * The pp stands for Pre Print Trace.
2680 function _ppt($mixed, $textOnly=false)
2685 * Private helper function for displaying the contents of a given variable.
2686 * This function is only intended to be used for SugarCRM internal development.
2687 * The pp stands for Pre Print Trace Die.
2689 function _pptd($mixed)
2694 * Private helper function for decoding javascript UTF8
2695 * This function is only intended to be used for SugarCRM internal development.
2697 function decodeJavascriptUTF8($str) {
2701 * Will check if a given PHP version string is supported (tested on this ver),
2702 * unsupported (results unknown), or invalid (something will break on this
2703 * ver). Do not pass in any pararameter to default to a check against the
2704 * current environment's PHP version.
2706 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2708 function check_php_version($sys_php_version = '') {
2709 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2710 // versions below $min_considered_php_version considered invalid by default,
2711 // versions equal to or above this ver will be considered depending
2712 // on the rules that follow
2713 $min_considered_php_version = '5.2.1';
2715 // only the supported versions,
2716 // should be mutually exclusive with $invalid_php_versions
2717 $supported_php_versions = array (
2718 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2721 // invalid versions above the $min_considered_php_version,
2722 // should be mutually exclusive with $supported_php_versions
2724 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2725 $invalid_php_versions = array('5.2.7');
2727 // default unsupported
2730 // versions below $min_considered_php_version are invalid
2731 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2735 // supported version check overrides default unsupported
2736 foreach($supported_php_versions as $ver) {
2737 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2743 // invalid version check overrides default unsupported
2744 foreach($invalid_php_versions as $ver) {
2745 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2751 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2752 //and the php version contains 'rh' characters
2753 if(strpos($sys_php_version, 'rh') !== false) {
2761 * Will check if a given IIS version string is supported (tested on this ver),
2762 * unsupported (results unknown), or invalid (something will break on this
2765 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2767 function check_iis_version($sys_iis_version = '') {
2769 $server_software = $_SERVER["SERVER_SOFTWARE"];
2771 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2772 $iis_version = $out[1][0];
2774 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2776 // versions below $min_considered_iis_version considered invalid by default,
2777 // versions equal to or above this ver will be considered depending
2778 // on the rules that follow
2779 $min_considered_iis_version = '6.0';
2781 // only the supported versions,
2782 // should be mutually exclusive with $invalid_iis_versions
2783 $supported_iis_versions = array ('6.0', '7.0',);
2784 $unsupported_iis_versions = array();
2785 $invalid_iis_versions = array('5.0',);
2787 // default unsupported
2790 // versions below $min_considered_iis_version are invalid
2791 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2795 // supported version check overrides default unsupported
2796 foreach($supported_iis_versions as $ver) {
2797 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2803 // unsupported version check overrides default unsupported
2804 foreach($unsupported_iis_versions as $ver) {
2805 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2811 // invalid version check overrides default unsupported
2812 foreach($invalid_iis_versions as $ver) {
2813 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2822 function pre_login_check(){
2823 global $action, $login_error;
2824 if(!empty($action)&& $action == 'Login'){
2826 if(!empty($login_error)){
2827 $login_error = htmlentities($login_error);
2828 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2829 $_SESSION['login_error'] = $login_error;
2831 function set_focus() {}
2832 if(document.getElementById("post_error")) {
2833 document.getElementById("post_error").innerHTML="'. $login_error. '";
2834 document.getElementById("cant_login").value=1;
2835 document.getElementById("login_button").disabled = true;
2836 document.getElementById("user_name").disabled = true;
2837 //document.getElementById("user_password").disabled = true;
2846 function sugar_cleanup($exit = false) {
2847 static $called = false;
2850 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2851 chdir(realpath(dirname(__FILE__) . '/..'));
2852 global $sugar_config;
2853 require_once('include/utils/LogicHook.php');
2854 LogicHook::initialize();
2855 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2857 //added this check to avoid errors during install.
2858 if (empty($sugar_config['dbconfig'])) {
2859 if ($exit) exit; else return;
2862 if (!class_exists('Tracker', true)) {
2863 require_once 'modules/Trackers/Tracker.php';
2866 // Now write the cached tracker_queries
2867 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2868 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2869 $GLOBALS['current_user']->savePreferencesToDB();
2872 //check to see if this is not an `ajax call AND the user preference error flag is set
2874 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2875 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2876 && ($_REQUEST['action']!='favorites' && $_REQUEST['action']!='DynamicAction')
2877 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2878 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2881 global $app_strings;
2882 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2883 $err_mess = $app_strings['ERROR_USER_PREFS'];
2884 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2887 ajaxStatus.flashStatus('$err_mess',7000);
2893 if(class_exists('DBManagerFactory')) {
2894 $db = DBManagerFactory::getInstance();
2902 register_shutdown_function('sugar_cleanup');
2906 check_logic_hook - checks to see if your custom logic is in the logic file
2907 if not, it will add it. If the file isn't built yet, it will create the file
2910 function check_logic_hook_file($module_name, $event, $action_array){
2911 require_once('include/utils/logic_utils.php');
2914 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2916 $hook_array = get_hook_array($module_name);
2918 if(check_existing_element($hook_array, $event, $action_array)==true){
2919 //the hook at hand is present, so do nothing
2924 if(!empty($hook_array[$event]))
2926 $logic_count = count($hook_array[$event]);
2929 if($action_array[0]==""){
2930 $action_array[0] = $logic_count + 1;
2932 $hook_array[$event][] = $action_array;
2935 //end if the file exists already
2938 if($action_array[0]==""){
2939 $action_array[0] = 1;
2941 $hook_array = array();
2942 $hook_array[$event][] = $action_array;
2943 //end if else file exists already
2945 if($add_logic == true){
2947 //reorder array by element[0]
2948 //$hook_array = reorder_array($hook_array, $event);
2949 //!!!Finish this above TODO
2951 $new_contents = replace_or_add_logic_type($hook_array);
2952 write_logic_file($module_name, $new_contents);
2954 //end if add_element is true
2957 //end function check_logic_hook_file
2960 function remove_logic_hook($module_name, $event, $action_array) {
2961 require_once('include/utils/logic_utils.php');
2964 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2965 // The file exists, let's make sure the hook is there
2966 $hook_array = get_hook_array($module_name);
2968 if(check_existing_element($hook_array, $event, $action_array)==true){
2969 // The hook is there, time to take it out.
2971 foreach ( $hook_array[$event] as $i => $hook ) {
2972 // We don't do a full comparison below just in case the filename changes
2973 if ( $hook[0] == $action_array[0]
2974 && $hook[1] == $action_array[1]
2975 && $hook[3] == $action_array[3]
2976 && $hook[4] == $action_array[4] ) {
2977 unset($hook_array[$event][$i]);
2981 $new_contents = replace_or_add_logic_type($hook_array);
2982 write_logic_file($module_name, $new_contents);
2988 function display_stack_trace($textOnly=false){
2990 $stack = debug_backtrace();
2992 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
3000 foreach($stack as $item) {
3006 if(isset($item['file']))
3007 $file = $item['file'];
3008 if(isset($item['class']))
3009 $class = $item['class'];
3010 if(isset($item['line']))
3011 $line = $item['line'];
3012 if(isset($item['function']))
3013 $function = $item['function'];
3017 $out .= '<font color="black"><b>';
3023 $out .= '</b></font><font color="blue">';
3026 $out .= "[L:{$line}]";
3029 $out .= '</font><font color="red">';
3032 $out .= "({$class}:{$function})";
3035 $out .= '</font><br>';
3047 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
3048 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
3049 $halt_script = true;
3051 case 2048: return; //depricated we have lots of these ignore them
3054 if ( error_reporting() & E_NOTICE ) {
3055 $halt_script = false;
3061 case E_USER_WARNING:
3062 case E_COMPILE_WARNING:
3063 case E_CORE_WARNING:
3066 $halt_script = false;
3071 case E_COMPILE_ERROR:
3075 $type = "Fatal Error";
3080 $type = "Parse Error";
3084 //don't know what it is might not be so bad
3085 $halt_script = false;
3086 $type = "Unknown Error ($errno)";
3089 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3091 display_stack_trace();
3101 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3103 set_error_handler('StackTraceErrorHandler');
3105 function get_sub_cookies($name){
3107 if(isset($_COOKIE[$name])){
3108 $subs = explode('#', $_COOKIE[$name]);
3109 foreach($subs as $cookie){
3110 if(!empty($cookie)){
3111 $cookie = explode('=', $cookie);
3113 $cookies[$cookie[0]] = $cookie[1];
3122 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3124 if(!empty($sub_object_array)){
3126 foreach($sub_object_array as $sub_object){
3128 //run_second level is set to true if you need to remove sub-sub components
3129 if($run_second_level==true){
3131 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3133 //end if run_second_level is true
3135 $sub_object->mark_deleted($sub_object->id);
3136 //end foreach sub component
3138 //end if this is not empty
3141 //end function mark_delete_components
3145 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3147 function return_bytes($val)
3150 $last = strtolower($val{strlen($val)-1});
3154 // The 'G' modifier is available since PHP 5.1.0
3167 * Adds the href HTML tags around any URL in the $string
3169 function url2html($string) {
3171 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3172 return $return_string;
3174 // End customization by Julian
3177 * tries to determine whether the Host machine is a Windows machine
3179 function is_windows() {
3180 static $is_windows = null;
3181 if (!isset($is_windows)) {
3182 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3188 * equivalent for windows filesystem for PHP's is_writable()
3189 * @param string file Full path to the file/dir
3190 * @return bool true if writable
3192 function is_writable_windows($file) {
3193 if($file{strlen($file)-1}=='/') {
3194 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3197 // the assumption here is that Windows has an inherited permissions scheme
3198 // any file that is a descendant of an unwritable directory will inherit
3199 // that property and will trigger a failure below.
3204 $file = str_replace("/", '\\', $file);
3206 if(file_exists($file)) {
3207 if (!($f = @sugar_fopen($file, 'r+')))
3213 if(!($f = @sugar_fopen($file, 'w')))
3222 * best guesses Timezone based on webserver's TZ settings
3224 function lookupTimezone($userOffset = 0)
3226 return TimeDate::guessTimezone($userOffset);
3229 function convert_module_to_singular($module_array){
3232 foreach($module_array as $key => $value){
3233 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3235 if($value=="Cases") {
3236 $module_array[$key] = "Case";
3238 if($key=="projecttask"){
3239 $module_array['ProjectTask'] = "Project Task";
3240 unset($module_array[$key]);
3244 return $module_array;
3246 //end function convert_module_to_singular
3250 * Given the bean_name which may be plural or singular return the singular
3251 * bean_name. This is important when you need to include files.
3253 function get_singular_bean_name($bean_name){
3254 global $beanFiles, $beanList;
3255 if(array_key_exists($bean_name, $beanList)){
3256 return $beanList[$bean_name];
3264 * Given the potential module name (singular name, renamed module name)
3265 * Return the real internal module name.
3267 function get_module_from_singular($singular) {
3269 // find the internal module name for a singular name
3270 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3272 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3274 foreach ($singular_modules as $mod_name=>$sin_name) {
3275 if ($singular == $sin_name and $mod_name != $sin_name) {
3281 // find the internal module name for a renamed module
3282 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3284 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3286 foreach ($moduleList as $mod_name=>$name) {
3287 if ($singular == $name and $mod_name != $name) {
3293 // if it's not a singular name, nor a renamed name, return the original value
3297 function get_label($label_tag, $temp_module_strings){
3298 global $app_strings;
3299 if(!empty($temp_module_strings[$label_tag])){
3301 $label_name = $temp_module_strings[$label_tag];
3303 if(!empty($app_strings[$label_tag])){
3304 $label_name = $app_strings[$label_tag];
3306 $label_name = $label_tag;
3311 //end function get_label
3315 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3317 $rel_list = array();
3319 foreach($focus->relationship_fields as $rel_key => $rel_value){
3320 if($rel_value == $relationship_name){
3321 $temp_bean = get_module_info($tar_rel_module);
3322 // echo $focus->$rel_key;
3323 $temp_bean->retrieve($focus->$rel_key);
3324 if($temp_bean->id!=""){
3326 $rel_list[] = $temp_bean;
3332 foreach($focus->field_defs as $field_name => $field_def){
3333 //Check if the relationship_name matches a "relate" field
3334 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3335 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3336 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3337 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3339 $temp_bean = get_module_info($tar_rel_module);
3340 // echo $focus->$field_def['id_name'];
3341 $temp_bean->retrieve($focus->$field_def['id_name']);
3342 if($temp_bean->id!=""){
3344 $rel_list[] = $temp_bean;
3347 //Check if the relationship_name matches a "link" in a relate field
3348 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3349 $temp_bean = get_module_info($tar_rel_module);
3350 // echo $focus->$rel_value['id_name'];
3351 $temp_bean->retrieve($focus->$rel_value['id_name']);
3352 if($temp_bean->id!=""){
3354 $rel_list[] = $temp_bean;
3360 // special case for unlisted parent-type relationships
3361 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3362 $temp_bean = get_module_info($tar_rel_module);
3363 $temp_bean->retrieve($focus->parent_id);
3364 if($temp_bean->id!=""){
3365 $rel_list[] = $temp_bean;
3372 //end function search_filter_rel_info
3375 function get_module_info($module_name){
3379 //Get dictionary and focus data for module
3380 $vardef_name = $beanList[$module_name];
3382 if($vardef_name=="aCase"){
3383 $class_name = "Case";
3385 $class_name = $vardef_name;
3388 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3392 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3394 $module_bean = new $vardef_name();
3395 return $module_bean;
3396 //end function get_module_table
3400 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3402 * @param string $moduleName
3404 function get_valid_bean_name($module_name){
3407 $vardef_name = $beanList[$module_name];
3408 if($vardef_name=="aCase"){
3409 $bean_name = "Case";
3411 $bean_name = $vardef_name;
3418 function checkAuthUserStatus(){
3425 * This function returns an array of phpinfo() results that can be parsed and
3426 * used to figure out what version we run, what modules are compiled in, etc.
3427 * @param $level int info level constant (1,2,4,8...64);
3428 * @return $returnInfo array array of info about the PHP environment
3429 * @author original by "code at adspeed dot com" Fron php.net
3430 * @author customized for Sugar by Chris N.
3432 function getPhpInfo($level=-1) {
3433 /** Name (constant) Value Description
3434 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3435 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3436 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3437 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3438 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3439 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3440 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3441 INFO_ALL -1 Shows all of the above. This is the default value.
3445 $phpinfo = ob_get_contents();
3448 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3449 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3450 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3451 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3454 $returnInfo = array();
3456 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3457 $returnInfo['PHP Version'] = $version[1];
3461 for ($i=1; $i<count($parsedInfo); $i++) {
3462 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3463 $vName = trim($match[1]);
3464 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3466 foreach ($parsedInfo2 AS $vOne) {
3467 $vPat = '<info>([^<]+)<\/info>';
3468 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3469 $vPat2 = "/$vPat\s*$vPat/";
3471 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3472 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3473 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3474 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3486 * This function will take a string that has tokens like {0}, {1} and will replace
3487 * those tokens with the args provided
3488 * @param $format string to format
3489 * @param $args args to replace
3490 * @return $result a formatted string
3492 function string_format($format, $args){
3496 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3497 * IN () fails and IN ('') works.
3499 if (count($args) == 1)
3502 $singleArgument = current($args);
3503 if (empty($singleArgument))
3505 return str_replace("{0}", "''", $result);
3510 for($i = 0; $i < count($args); $i++){
3511 $result = str_replace('{'.$i.'}', $args[$i], $result);
3517 * Generate a string for displaying a unique identifier that is composed
3518 * of a system_id and number. This is use to allow us to generate quote
3519 * numbers using a DB auto-increment key from offline clients and still
3520 * have the number be unique (since it is modified by the system_id.
3522 * @param $num of bean
3523 * @param $system_id from system
3524 * @return $result a formatted string
3526 function format_number_display($num, $system_id){
3527 global $sugar_config;
3528 if(isset($num) && !empty($num)){
3529 $num=unformat_number($num);
3530 if(isset($system_id) && $system_id == 1){
3531 return sprintf("%d", $num);
3534 return sprintf("%d-%d", $num, $system_id);
3538 function checkLoginUserStatus(){
3542 * This function will take a number and system_id and format
3543 * @param $url URL containing host to append port
3544 * @param $port the port number - if '' is passed, no change to url
3545 * @return $resulturl the new URL with the port appended to the host
3547 function appendPortToHost($url, $port)
3551 // if no port, don't change the url
3554 $split = explode("/", $url);
3555 //check if it starts with http, in case they didn't include that in url
3556 if(str_begin($url, 'http'))
3558 //third index ($split[2]) will be the host
3559 $split[2] .= ":".$port;
3561 else // otherwise assumed to start with host name
3563 //first index ($split[0]) will be the host
3564 $split[0] .= ":".$port;
3567 $resulturl = implode("/", $split);
3574 * Singleton to return JSON object
3575 * @return JSON object
3577 function getJSONobj() {
3578 static $json = null;
3580 require_once('include/JSON.php');
3581 $json = new JSON(JSON_LOOSE_TYPE);
3586 require_once('include/utils/db_utils.php');
3589 * Set default php.ini settings for entry points
3591 function setPhpIniSettings() {
3593 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3595 if(function_exists('gzclose') && headers_sent() == false) {
3596 ini_set('zlib.output_compression', 1);
3600 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3602 /*if(function_exists('mb_strlen')) {
3603 ini_set('mbstring.func_overload', 7);
3604 ini_set('mbstring.internal_encoding', 'UTF-8');
3608 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3609 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3610 $backtrack_limit = ini_get('pcre.backtrack_limit');
3611 if(!empty($backtrack_limit)) {
3612 ini_set('pcre.backtrack_limit', '-1');
3617 * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
3618 * language files. Language file merges do not need to account for null values so we can get some
3619 * performance increases by using this specialized function. Note this merge function does not properly
3620 * handle null values.
3626 function sugarLangArrayMerge($gimp, $dom)
3628 if(is_array($gimp) && is_array($dom))
3630 foreach($dom as $domKey => $domVal)
3632 if(isset($gimp[$domKey]))
3634 if(is_array($domVal))
3637 foreach ( $domVal as $domArrKey => $domArrVal )
3638 $tempArr[$domArrKey] = $domArrVal;
3639 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3640 if ( !isset($tempArr[$gimpArrKey]) )
3641 $tempArr[$gimpArrKey] = $gimpArrVal;
3642 $gimp[$domKey] = $tempArr;
3646 $gimp[$domKey] = $domVal;
3651 $gimp[$domKey] = $domVal;
3655 // if the passed value for gimp isn't an array, then return the $dom
3656 elseif(is_array($dom))
3664 * like array_merge() but will handle array elements that are themselves arrays;
3665 * PHP's version just overwrites the element with the new one.
3667 * @internal Note that this function deviates from the internal array_merge()
3668 * functions in that it does does not treat numeric keys differently
3669 * than string keys. Additionally, it deviates from
3670 * array_merge_recursive() by not creating an array when like values
3673 * @param array gimp the array whose values will be overloaded
3674 * @param array dom the array whose values will pwn the gimp's
3675 * @return array beaten gimp
3677 function sugarArrayMerge($gimp, $dom) {
3678 if(is_array($gimp) && is_array($dom)) {
3679 foreach($dom as $domKey => $domVal) {
3680 if(array_key_exists($domKey, $gimp)) {
3681 if(is_array($domVal)) {
3683 foreach ( $domVal as $domArrKey => $domArrVal )
3684 $tempArr[$domArrKey] = $domArrVal;
3685 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3686 if ( !array_key_exists($gimpArrKey, $tempArr) )
3687 $tempArr[$gimpArrKey] = $gimpArrVal;
3688 $gimp[$domKey] = $tempArr;
3690 $gimp[$domKey] = $domVal;
3693 $gimp[$domKey] = $domVal;
3697 // if the passed value for gimp isn't an array, then return the $dom
3698 elseif(is_array($dom))
3705 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3707 * @param array gimp the array whose values will be overloaded
3708 * @param array dom the array whose values will pwn the gimp's
3709 * @return array beaten gimp
3711 function sugarArrayMergeRecursive($gimp, $dom) {
3712 if(is_array($gimp) && is_array($dom)) {
3713 foreach($dom as $domKey => $domVal) {
3714 if(array_key_exists($domKey, $gimp)) {
3715 if(is_array($domVal) && is_array($gimp[$domKey])) {
3716 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3718 $gimp[$domKey] = $domVal;
3721 $gimp[$domKey] = $domVal;
3725 // if the passed value for gimp isn't an array, then return the $dom
3726 elseif(is_array($dom))
3733 * finds the correctly working versions of PHP-JSON
3734 * @return bool True if NOT found or WRONG version
3736 function returnPhpJsonStatus() {
3737 if(function_exists('json_encode')) {
3738 $phpInfo = getPhpInfo(8);
3739 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3741 return true; // not found
3746 * getTrackerSubstring
3748 * Returns a [number]-char or less string for the Tracker to display in the header
3749 * based on the tracker_max_display_length setting in config.php. If not set,
3750 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3752 * @param string name field for a given Object
3753 * @return string [number]-char formatted string if length of string exceeds the max allowed
3755 function getTrackerSubstring($name) {
3756 static $max_tracker_item_length;
3759 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3760 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3762 global $sugar_config;
3764 if(!isset($max_tracker_item_length)) {
3765 if(isset($sugar_config['tracker_max_display_length'])) {
3766 $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;
3768 $max_tracker_item_length = 15;
3772 if($strlen > $max_tracker_item_length) {
3773 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length);
3780 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3781 $where_clauses= array();
3783 $table_name=$bean->object_name;
3784 foreach ($field_list[$module] as $field=>$parms) {
3785 if(isset($values[$field]) && $values[$field] != "") {
3787 if (!empty($parms['operator'])) {
3788 $operator=$parms['operator'];
3790 if (is_array($values[$field])) {
3793 foreach ($values[$field] as $key => $val) {
3794 if ($val != ' ' and $val != '') {
3795 if (!empty($field_value)) {
3798 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3802 $field_value=$GLOBALS['db']->quote($values[$field]);
3804 //set db_fields array.
3805 if (!isset($parms['db_field']) ) {
3806 $parms['db_field'] = array($field);
3808 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3809 global $current_user;
3810 $field_value = $GLOBALS['db']->quote($current_user->id);
3816 if ($field_value != '') {
3818 foreach ($parms['db_field'] as $db_field) {
3819 if (strstr($db_field,'.')===false) {
3820 $db_field=$bean->table_name.".".$db_field;
3822 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3823 $db_field='upper('.$db_field.")";
3824 $field_value=strtoupper($field_value);
3828 if (!empty($where)) {
3831 switch (strtolower($operator)) {
3833 $where .= $db_field . " like '".$field_value.$like_char."'";
3836 $where .= $db_field . " in (".$field_value.')';
3839 $where .= $db_field . " = '".$field_value ."'";
3844 if (!empty($where)) {
3846 array_push($where_clauses, '( '.$where.' )');
3848 array_push($where_clauses, $where);
3853 if ($add_custom_fields) {
3854 require_once('modules/DynamicFields/DynamicField.php');
3855 $bean->setupCustomFields($module);
3856 $bean->custom_fields->setWhereClauses($where_clauses);
3858 return $where_clauses;
3861 function add_quotes($str) {
3866 * This function will rebuild the config file
3867 * @param $sugar_config
3868 * @param $sugar_version
3869 * @return bool true if successful
3871 function rebuildConfigFile($sugar_config, $sugar_version) {
3872 // add defaults to missing values of in-memory sugar_config
3873 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3874 // need to override version with default no matter what
3875 $sugar_config['sugar_version'] = $sugar_version;
3877 ksort( $sugar_config );
3879 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3888 * getJavascriptSiteURL
3889 * This function returns a URL for the client javascript calls to access
3890 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3891 * are used to access the site. Thus, the hostname in the URL returned may
3892 * not always match that of $sugar_config['site_url']. Basically, the
3893 * assumption is that however the user accessed the website is how they
3894 * will continue to with subsequent javascript requests. If the variable
3895 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3896 * @return $site_url The url used to refer to the website
3898 function getJavascriptSiteURL() {
3899 global $sugar_config;
3900 if(!empty($_SERVER['HTTP_REFERER'])) {
3901 $url = parse_url($_SERVER['HTTP_REFERER']);
3902 $replacement_url = $url['scheme']."://".$url['host'];
3903 if(!empty($url['port']))
3904 $replacement_url .= ':'.$url['port'];
3905 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3907 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3908 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3909 $site_url = preg_replace('/^http\:/','https:',$site_url);
3912 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3916 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3917 function add_squotes($str) {
3918 return "'" . $str . "'";
3922 // recursive function to count the number of levels within an array
3923 function array_depth($array, $depth_count=-1, $depth_array=array()){
3925 if (is_array($array)){
3926 foreach ($array as $key => $value){
3927 $depth_array[] = array_depth($value, $depth_count);
3931 return $depth_count;
3933 foreach ($depth_array as $value){
3934 $depth_count = $value > $depth_count ? $value : $depth_count;
3936 return $depth_count;
3940 * Creates a new Group User
3941 * @param string $name Name of Group User
3942 * @return string GUID of new Group User
3944 function createGroupUser($name) {
3947 $group = new User();
3948 $group->user_name = $name;
3949 $group->last_name = $name;
3950 $group->is_group = 1;
3951 $group->deleted = 0;
3952 $group->status = 'Active'; // cn: bug 6711
3953 $group->setPreference('timezone', TimeDate::userTimezone());
3960 * Helper function to locate an icon file given only a name
3961 * Searches through the various paths for the file
3962 * @param string iconFileName The filename of the icon
3963 * @return string Relative pathname of the located icon, or '' if not found
3966 function _getIcon($iconFileName)
3969 $iconName = "icon_{$iconFileName}.gif";
3970 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3972 //First try un-ucfirst-ing the icon name
3973 if ( empty($iconFound) )
3974 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3975 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3977 //Next try removing the icon prefix
3978 if ( empty($iconFound) )
3979 $iconName = "{$iconFileName}.gif";
3980 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3982 if ( empty($iconFound) )
3988 * Function to grab the correct icon image for Studio
3989 * @param string $iconFileName Name of the icon file
3990 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3991 * @param string $width Width of image
3992 * @param string $height Height of image
3993 * @param string $align Alignment of image
3994 * @param string $alt Alt tag of image
3995 * @return string $string <img> tag with corresponding image
3998 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
4000 global $app_strings, $theme;
4002 $iconName = _getIcon($iconFileName);
4003 if(empty($iconName)){
4004 $iconName = _getIcon($altFileName);
4005 if (empty($iconName))
4007 return $app_strings['LBL_NO_IMAGE'];
4010 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4014 * Function to grab the correct icon image for Dashlets Dialog
4015 * @param string $filename Location of the icon file
4016 * @param string $module Name of the module to fall back onto if file does not exist
4017 * @param string $width Width of image
4018 * @param string $height Height of image
4019 * @param string $align Alignment of image
4020 * @param string $alt Alt tag of image
4021 * @return string $string <img> tag with corresponding image
4024 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
4025 global $app_strings, $theme;
4026 $iconName = _getIcon($module . "_32");
4027 if (empty($iconName))
4029 $iconName = _getIcon($module);
4031 if(empty($iconName)){
4032 return $app_strings['LBL_NO_IMAGE'];
4034 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4037 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
4038 function html_entity_decode_utf8($string)
4041 // replace numeric entities
4042 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
4043 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
4044 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
4045 // replace literal entities
4046 if (!isset($trans_tbl))
4048 $trans_tbl = array();
4049 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
4050 $trans_tbl[$key] = utf8_encode($val);
4052 return strtr($string, $trans_tbl);
4055 // Returns the utf string corresponding to the unicode value
4056 function code2utf($num)
4058 if ($num < 128) return chr($num);
4059 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
4060 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4061 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4065 function str_split_php4($string, $length = 1) {
4066 $string_length = strlen($string);
4069 if ($length > $string_length) {
4070 // use the string_length as the string is shorter than the length
4071 $length = $string_length;
4073 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
4074 $return[] = substr($string, $cursor, $length);
4079 if (version_compare(phpversion(), '5.0.0', '<')) {
4080 function str_split($string, $length = 1) {
4081 return str_split_php4($string, $length);
4086 * @deprecated use DBManagerFactory::isFreeTDS
4088 function is_freetds()
4090 return DBManagerFactory::isFreeTDS();
4094 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
4096 * @todo this won't work completely right until we impliment css compression and combination
4097 * for now, we'll just include the last css file found.
4099 * @return chart.css file to use
4101 function chartStyle()
4103 return SugarThemeRegistry::current()->getCSSURL('chart.css');
4107 * Chart dashlet helper functions that returns the correct XML color file for charts,
4108 * dependent on the current theme.
4110 * @return sugarColors.xml to use
4112 function chartColors()
4114 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
4115 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4116 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4118 /* End Chart Dashlet helper functions */
4121 * This function is designed to set up the php enviroment
4122 * for AJAX requests.
4125 function ajaxInit() {
4126 ini_set('display_errors', 'false');
4130 * Returns an absolute path from the given path, determining if it is relative or absolute
4132 * @param string $path
4135 function getAbsolutePath(
4137 $currentServer = false
4140 $path = trim($path);
4142 // try to match absolute paths like \\server\share, /directory or c:\
4143 if ( ( substr($path,0,2) == '\\\\' )
4144 || ( $path[0] == '/' )
4145 || preg_match('/^[A-z]:/i',$path)
4149 return getcwd().'/'.$path;
4153 * Returns the bean object of the given module
4155 * @deprecated use SugarModule::loadBean() instead
4156 * @param string $module
4163 return SugarModule::get($module)->loadBean();
4168 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4170 function isTouchScreen()
4172 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4174 // first check if we have forced use of the touch enhanced interface
4175 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4179 // next check if we should use the touch interface with our device
4180 if ( strpos($ua, 'ipad') !== false ) {
4188 * Returns the shortcut keys to access the shortcut links. Shortcut
4189 * keys vary depending on browser versions and operating systems.
4190 * @return String value of the shortcut keys
4192 function get_alt_hot_key() {
4194 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4195 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4196 $isMac = strpos($ua, 'mac') !== false;
4197 $isLinux = strpos($ua, 'linux') !== false;
4199 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4200 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4201 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4204 return $isMac ? 'Ctrl+' : 'Alt+';
4207 function can_start_session(){
4208 if(!empty($_GET['PHPSESSID'])) {
4211 $session_id = session_id();
4212 return empty($session_id) ? true : false;
4215 function load_link_class($properties){
4217 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4218 require_once($properties['link_file']);
4219 $class = $properties['link_class'];
4225 function inDeveloperMode()
4227 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4231 * Filter the protocol list for inbound email accounts.
4233 * @param array $protocol
4235 function filterInboundEmailPopSelection($protocol)
4237 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4239 if( isset($protocol['pop3']) )
4240 unset($protocol['pop3']);
4243 $protocol['pop3'] = 'POP3';
4249 * The function is used because currently we are not supporting mbstring.func_overload
4250 * 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.
4251 * 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.
4252 * @returns the substred strings.
4254 function sugar_substr($string, $length, $charset='UTF-8')
4256 if(mb_strlen($string,$charset) > $length) {
4257 $string = trim(mb_substr(trim($string),0,$length,$charset));
4263 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4264 * This will work even without setting the mbstring.*encoding
4266 function sugar_ucfirst($string, $charset='UTF-8') {
4267 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4274 function unencodeMultienum($string) {
4275 if (is_array($string))
4279 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4280 $string = substr(substr($string, 1), 0, strlen($string) -2);
4283 return explode('^,^', $string);
4286 function encodeMultienumValue($arr) {
4287 if (!is_array($arr))
4293 $string = "^" . implode('^,^', $arr) . "^";
4299 * create_export_query is used for export and massupdate
4300 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4301 * This function will correct the where clause and output necessary join condition for them
4302 * @param $module: the module name
4303 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4304 * @param $where: where clauses
4305 * @return $ret_array['where']: corrected where clause
4306 * @return $ret_array['join']: extra join condition
4308 function create_export_query_relate_link_patch($module, $searchFields, $where){
4309 if(file_exists('modules/'.$module.'/SearchForm.html')){
4310 $ret_array['where'] = $where;
4313 $seed = loadBean($module);
4314 foreach($seed->field_defs as $name=>$field)
4317 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4318 $seed->load_relationship($field['link']);
4320 if(empty($join_type))
4322 $params['join_type'] = ' LEFT JOIN ';
4326 $params['join_type'] = $join_type;
4328 if(isset($data['join_name']))
4330 $params['join_table_alias'] = $field['join_name'];
4334 $params['join_table_alias'] = 'join_'.$field['name'];
4337 if(isset($data['join_link_name']))
4339 $params['join_table_link_alias'] = $field['join_link_name'];
4343 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4345 $join = $seed->$field['link']->getJoin($params, true);
4346 $join_table_alias = 'join_'.$field['name'];
4347 if(isset($field['db_concat_fields'])){
4348 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4349 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4351 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4355 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4360 * 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.
4361 * @Depends on QuickRepairAndRebuild.php
4362 * @Relate bug 30642 ,23177
4364 function clearAllJsAndJsLangFilesWithoutOutput(){
4365 global $current_language , $mod_strings;
4366 $MBmodStrings = $mod_strings;
4367 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4368 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4369 $repair = new RepairAndClear();
4370 $repair->module_list = array();
4371 $repair->show_output = false;
4372 $repair->clearJsLangFiles();
4373 $repair->clearJsFiles();
4374 $mod_strings = $MBmodStrings;
4378 * This function will allow you to get a variable value from query string
4380 function getVariableFromQueryString($variable, $string){
4382 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4392 * should_hide_iframes
4393 * This is a helper method to determine whether or not to show iframes (My Sites) related
4394 * information in the application.
4396 * @return boolean flag indicating whether or not iframes module should be hidden
4398 function should_hide_iframes() {
4399 //Remove the MySites module
4400 if(file_exists('modules/iFrames/iFrame.php')) {
4401 if(!class_exists("iFrame")) {
4402 require_once('modules/iFrames/iFrame.php');
4410 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4412 * @param string $version
4413 * @return string RC, BETA, GA
4415 function getVersionStatus($version){
4416 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4417 return strtoupper($matches[1]);
4424 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4425 * 5.5.1RC1 then return 5.5.1
4427 * @param string $version
4430 function getMajorMinorVersion($version){
4431 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4432 $version = $matches2[1];
4433 $arr = explode('.', $version);
4434 if(count($arr) > 2){
4436 $version = substr($version, 0, 3);
4444 * Return string composed of seconds & microseconds of current time, without dots
4447 function sugar_microtime()
4449 $now = explode(' ', microtime());
4450 $unique_id = $now[1].str_replace('.', '', $now[0]);
4455 * Extract urls from a piece of text
4457 * @return array of urls found in $string
4459 function getUrls($string)
4461 $lines = explode("<br>", trim($string));
4463 foreach($lines as $line){
4464 $regex = '/http?\:\/\/[^\" ]+/i';
4465 preg_match_all($regex, $line, $matches);
4466 foreach($matches[0] as $match){
4475 * Sanitize image file from hostile content
4476 * @param string $path Image file
4477 * @param bool $jpeg Accept only JPEGs?
4479 function verify_image_file($path, $jpeg = false)
4481 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4482 $img = imagecreatefromstring(file_get_contents($path));
4486 $img_size = getimagesize($path);
4487 $filetype = $img_size['mime'];
4488 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4489 if($filetype == "image/jpeg" || $jpeg) {
4492 $image = ob_get_clean();
4493 // not writing directly because imagejpeg does not work with streams
4494 if(file_put_contents($path, $image)) {
4497 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4498 imagealphablending($img, true);
4499 imagesavealpha($img, true);
4502 $image = ob_get_clean();
4503 if(file_put_contents($path, $image)) {
4510 // check image manually
4511 $fp = fopen($path, "r");
4512 if(!$fp) return false;
4513 $data = fread($fp, 4096);
4515 if(preg_match("/<(html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
4517 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4526 * Verify uploaded image
4527 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4528 * @param string $path Image path
4529 * @param bool $jpeg_only Accept only JPEGs?
4531 function verify_uploaded_image($path, $jpeg_only = false)
4533 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4535 $supportedExtensions['png'] = 'image/png';
4538 if(!file_exists($path) || !is_file($path)) {
4542 $img_size = getimagesize($path);
4543 $filetype = $img_size['mime'];
4544 $ext = end(explode(".", $path));
4545 if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4546 !in_array($filetype, array_values($supportedExtensions))) {
4549 return verify_image_file($path, $jpeg_only);
4552 function cmp_beans($a, $b)
4554 global $sugar_web_service_order_by;
4555 //If the order_by field is not valid, return 0;
4556 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4559 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4560 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4564 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4572 function order_beans($beans, $field_name)
4574 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4575 global $sugar_web_service_order_by;
4576 $sugar_web_service_order_by = $field_name;
4577 usort($beans, "cmp_beans");
4582 * Return search like string
4583 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4584 * @param string $str string to be searched
4585 * @param string $like_char Database like character, usually '%'
4586 * @return string Returns a string to be searched in db query
4588 function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true) {
4590 // override default wildcard character
4591 if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4592 strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4593 $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4596 // add wildcard at the beginning of the search string
4597 if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4598 $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4599 if (substr($str,0,1) <> $wildcard)
4600 $str = $wildcard.$str;
4603 // add wildcard at the end of search string (default)
4604 if ($appendWildcard) {
4605 if(substr($str,-1) <> $wildcard) {
4610 return str_replace($wildcard, $like_char, $str);
4613 //check to see if custom utils exists
4614 if(file_exists('custom/include/custom_utils.php')){
4615 include_once('custom/include/custom_utils.php');
4618 //check to see if custom utils exists in Extension framework
4619 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4620 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4623 * @param $input - the input string to sanitize
4624 * @param int $quotes - use quotes
4625 * @param string $charset - the default charset
4626 * @param bool $remove - strip tags or not
4627 * @return string - the sanitized string
4629 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4631 return htmlentities($input, $quotes, $charset);
4635 * @return string - the full text search engine name
4637 function getFTSEngineType()
4639 if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
4640 foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
4648 * @param string $optionName - name of the option to be retrieved from app_list_strings
4649 * @return array - the array to be used in option element
4651 function getFTSBoostOptions($optionName)
4653 if (isset($GLOBALS['app_list_strings'][$optionName])) {
4654 return $GLOBALS['app_list_strings'][$optionName];
4662 * utf8_recursive_encode
4664 * This function walks through an Array and recursively calls utf8_encode on the
4665 * values of each of the elements.
4667 * @param $data Array of data to encode
4668 * @return utf8 encoded Array data
4670 function utf8_recursive_encode($data)
4673 foreach($data as $key=>$val) {
4674 if(is_array($val)) {
4675 $result[$key] = utf8_recursive_encode($val);
4677 $result[$key] = utf8_encode($val);
4684 * get_language_header
4686 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4687 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4689 * @return String The lang=[Current Language] markup to insert into the <html> tag
4691 function get_language_header()
4693 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4698 * get_custom_file_if_exists
4700 * This function handles the repetitive code we have where we first check if a file exists in the
4701 * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
4702 * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
4703 * otherwise it return $file
4705 * @param $file String of filename to check
4706 * @return $file String of filename including custom directory if found
4708 function get_custom_file_if_exists($file)
4710 return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4717 * This will return the URL used to redirect the user to the help documentation.
4718 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4719 * in config.php or config_override.php.
4721 * @param string $send_edition
4722 * @param string $send_version
4723 * @param string $send_lang
4724 * @param string $send_module
4725 * @param string $send_action
4726 * @param string $dev_status
4727 * @param string $send_key
4728 * @param string $send_anchor
4729 * @return string the completed help URL
4731 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4732 global $sugar_config;
4734 if (!empty($sugar_config['custom_help_url'])) {
4735 $sendUrl = $sugar_config['custom_help_url'];
4737 if (!empty($sugar_config['custom_help_base_url'])) {
4738 $baseUrl= $sugar_config['custom_help_base_url'];
4740 $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4742 $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4743 if(!empty($send_anchor)) {
4744 $sendUrl .= "&anchor=".$send_anchor;