2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
37 /*********************************************************************************
39 * Description: Includes generic helper functions used throughout the application.
40 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41 * All Rights Reserved.
42 * Contributor(s): ______________________________________..
43 ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/security_utils.php');
49 function make_sugar_config(&$sugar_config)
51 /* used to convert non-array config.php file to array format */
52 global $admin_export_only;
54 global $calculate_response_time;
55 global $create_default_user;
58 global $dbconfigoption;
59 global $default_action;
60 global $default_charset;
61 global $default_currency_name;
62 global $default_currency_symbol;
63 global $default_currency_iso4217;
64 global $defaultDateFormat;
65 global $default_language;
66 global $default_module;
67 global $default_password;
68 global $default_permission_mode;
69 global $default_theme;
70 global $defaultTimeFormat;
71 global $default_user_is_admin;
72 global $default_user_name;
73 global $disable_export;
74 global $disable_persistent_connections;
75 global $display_email_template_variable_chooser;
76 global $display_inbound_email_buttons;
77 global $history_max_viewed;
81 global $list_max_entries_per_page;
82 global $lock_default_user_name;
83 global $log_memory_usage;
85 global $requireAccounts;
86 global $RSS_CACHE_TIME;
90 global $sugar_version;
93 global $translation_string_prefix;
95 global $upload_badext;
97 global $upload_maxsize;
98 global $import_max_execution_time;
99 global $list_max_entries_per_subpanel;
100 global $passwordsetting;
102 // assumes the following variables must be set:
103 // $dbconfig, $dbconfigoption, $cache_dir, $session_dir, $site_URL, $upload_dir
105 $sugar_config = array (
106 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
107 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
108 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
109 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
110 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
111 'chartEngine' => 'Jit',
112 'date_formats' => empty($dateFormats) ? array(
113 'Y-m-d'=>'2010-12-23',
114 'd-m-Y' => '23-12-2010',
115 'm-d-Y'=>'12-23-2010',
116 'Y/m/d'=>'2010/12/23',
117 'd/m/Y' => '23/12/2010',
118 'm/d/Y'=>'12/23/2010',
119 'Y.m.d' => '2010.12.23',
120 'd.m.Y' => '23.12.2010',
121 'm.d.Y' => '12.23.2010'
123 'dbconfig' => $dbconfig, // this must be set!!
124 'dbconfigoption' => $dbconfigoption, // this must be set!!
125 'default_action' => empty($default_action) ? 'index' : $default_action,
126 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
127 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
128 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
129 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
130 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
131 'default_locale_name_format' => empty($defaultNameFormat) ? 's f l' : $defaultNameFormat,
132 'default_export_charset' => 'UTF-8',
133 'default_language' => empty($default_language) ? 'en_us' : $default_language,
134 'default_module' => empty($default_module) ? 'Home' : $default_module,
135 'default_password' => empty($default_password) ? '' : $default_password,
136 'default_permissions' => array (
142 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
143 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
144 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
145 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
146 'disable_export' => empty($disable_export) ? false : $disable_export,
147 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
148 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
149 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
150 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
151 'host_name' => empty($host_name) ? 'localhost' : $host_name,
152 'import_dir' => $import_dir, // this must be set!!
153 'import_max_records_per_file' => 100,
154 'import_max_records_total_limit' => '',
155 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
156 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
157 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
158 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
159 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
160 'name_formats' => empty($nameFormats) ? array(
161 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
162 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
164 'portal_view' => 'single_user',
165 'resource_management' => array (
166 'special_query_limit' => 50000,
167 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
168 'default_limit' => 1000,
170 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
171 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
172 'session_dir' => $session_dir, // this must be set!!
173 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
174 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
175 'showThemePicker' => true,
176 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
177 'time_formats' => empty($timeFormats) ? array (
178 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
179 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
180 'tmp_dir' => $tmp_dir, // this must be set!!
181 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
182 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
183 'upload_badext' => empty($upload_badext) ? array (
184 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
185 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
186 'upload_dir' => $upload_dir, // this must be set!!
187 'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
188 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
189 'lock_homepage' => false,
190 'lock_subpanels' => false,
191 'max_dashlets_homepage' => 15,
192 'dashlet_display_row_options' => array('1','3','5','10'),
193 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
194 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
195 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
196 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
197 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
198 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
199 'default_call_status' => 'Planned',
200 'js_lang_version' => 1,
201 'passwordsetting' => empty($passwordsetting) ? array (
202 'SystemGeneratedPasswordON' => '',
203 'generatepasswordtmpl' => '',
204 'lostpasswordtmpl' => '',
205 'forgotpasswordON' => true,
206 'linkexpiration' => '1',
207 'linkexpirationtime' => '30',
208 'linkexpirationtype' => '1',
209 'systexpiration' => '0',
210 'systexpirationtime' => '',
211 'systexpirationtype' => '0',
212 'systexpirationlogin' => '',
213 ) : $passwordsetting,
214 'use_sprites' => function_exists('imagecreatetruecolor'),
215 'search_wildcard_infront' => false,
216 'search_wildcard_char' => '%',
218 'min_retry_interval' => 60, // minimal job retry delay
219 'max_retries' => 5, // how many times to retry the job
220 'timeout' => 86400, // how long a job may spend as running before being force-failed
223 'max_cron_jobs' => 10, // max jobs per cron schedule run
224 'max_cron_runtime' => 60, // max runtime for cron jobs
225 'min_cron_interval' => 30, // minimal interval between cron jobs
230 function get_sugar_config_defaults() {
233 * used for getting base values for array style config.php. used by the
234 * installer and to fill in new entries on upgrades. see also:
238 $sugar_config_defaults = array (
239 'admin_export_only' => false,
240 'export_delimiter' => ',',
241 'cache_dir' => 'cache/',
242 'calculate_response_time' => true,
243 'create_default_user' => false,
244 'chartEngine' => 'Jit',
245 'date_formats' => array (
246 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
247 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
248 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
249 'name_formats' => array (
250 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
251 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
253 'dbconfigoption' => array (
254 'persistent' => true,
258 'default_action' => 'index',
259 'default_charset' => return_session_value_or_default('default_charset',
261 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
262 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
263 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
264 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
265 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
266 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
267 'default_date_format' => 'm/d/Y',
268 'default_locale_name_format' => 's f l',
269 'default_export_charset' => 'UTF-8',
270 'default_language' => return_session_value_or_default('default_language',
272 'default_module' => 'Home',
273 'default_password' => '',
274 'default_permissions' => array (
280 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
281 'default_time_format' => 'h:ia',
282 'default_user_is_admin' => false,
283 'default_user_name' => '',
284 'disable_export' => false,
285 'disable_persistent_connections' =>
286 return_session_value_or_default('disable_persistent_connections',
288 'display_email_template_variable_chooser' => false,
289 'display_inbound_email_buttons' => false,
290 'dump_slow_queries' => false,
291 'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
292 'email_default_editor' => 'html',
293 'email_default_client' => 'sugar',
294 'email_default_delete_attachments' => true,
295 'history_max_viewed' => 50,
296 'installer_locked' => true,
297 'import_max_records_per_file' => 100,
298 'import_max_records_total_limit' => '',
299 'languages' => array('en_us' => 'English (US)'),
300 'large_scale_test' => false,
301 'list_max_entries_per_page' => 20,
302 'list_max_entries_per_subpanel' => 10,
303 'lock_default_user_name' => false,
304 'log_memory_usage' => false,
305 'portal_view' => 'single_user',
306 'resource_management' => array (
307 'special_query_limit' => 50000,
308 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
309 'default_limit' => 1000,
311 'require_accounts' => true,
312 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
314 'save_query' => 'all',
315 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
316 'showThemePicker' => true,
317 'slow_query_time_msec' => '100',
319 'time_formats' => array (
320 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
321 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
322 'tracker_max_display_length' => 15,
323 'translation_string_prefix' =>
324 return_session_value_or_default('translation_string_prefix', false),
325 'upload_badext' => array (
326 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
327 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
328 'upload_maxsize' => 30000000,
329 'import_max_execution_time' => 3600,
330 // 'use_php_code_json' => returnPhpJsonStatus(),
331 'verify_client_ip' => true,
332 'js_custom_version' => '',
333 'js_lang_version' => 1,
334 'lead_conv_activity_opt' => 'donothing',
335 'default_number_grouping_seperator' => ',',
336 'default_decimal_seperator' => '.',
337 'lock_homepage' => false,
338 'lock_subpanels' => false,
339 'max_dashlets_homepage' => '15',
340 'default_max_tabs' => '7',
341 'dashlet_display_row_options' => array('1','3','5','10'),
342 'default_subpanel_tabs' => true,
343 'default_subpanel_links' => false,
344 'default_swap_last_viewed' => false,
345 'default_swap_shortcuts' => false,
346 'default_navigation_paradigm' => 'gm',
347 'admin_access_control' => false,
348 'use_common_ml_dir' => false,
349 'common_ml_dir' => '',
352 'default_view' => 'week',
353 'show_calls_by_default' => true,
354 'show_tasks_by_default' => true,
355 'editview_width' => 990,
356 'editview_height' => 485,
357 'day_timestep' => 15,
358 'week_timestep' => 30,
359 'items_draggable' => true,
360 'items_resizable' => true,
361 'enable_repeat' => true,
362 'max_repeat_count' => 1000,
364 'passwordsetting' => empty($passwordsetting) ? array (
365 'SystemGeneratedPasswordON' => '',
366 'generatepasswordtmpl' => '',
367 'lostpasswordtmpl' => '',
368 'forgotpasswordON' => false,
369 'linkexpiration' => '1',
370 'linkexpirationtime' => '30',
371 'linkexpirationtype' => '1',
372 'systexpiration' => '0',
373 'systexpirationtime' => '',
374 'systexpirationtype' => '0',
375 'systexpirationlogin' => '',
376 ) : $passwordsetting,
377 'use_real_names' => true,
379 'search_wildcard_infront' => false,
380 'search_wildcard_char' => '%',
382 'min_retry_interval' => 30, // 30 seconds minimal job retry
383 'max_retries' => 5, // how many times to retry the job
384 'timeout' => 86400, // how long a job may spend as running before being force-failed
387 'max_cron_jobs' => 10, // max jobs per cron schedule run
388 'max_cron_runtime' => 30, // max runtime for cron jobs
389 'min_cron_interval' => 30, // minimal interval between cron jobs
393 if(!is_object($locale)) {
394 $locale = new Localization();
397 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
399 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
400 return( $sugar_config_defaults );
404 * @deprecated use SugarView::getMenu() instead
406 function load_menu($path){
409 if(file_exists($path . 'Menu.php'))
411 require($path . 'Menu.php');
413 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
415 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
417 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
419 require('custom/application/Ext/Menus/menu.ext.php');
425 * get_notify_template_file
426 * This function will return the location of the email notifications template to use
428 * @return string relative file path to email notifications template file
430 function get_notify_template_file($language){
432 * Order of operation:
433 * 1) custom version of specified language
434 * 2) stock version of specified language
435 * 3) custom version of en_us template
436 * 4) stock en_us template
439 // set $file to the base code template so it's set if none of the conditions pass
440 $file = "include/language/en_us.notify_template.html";
442 if(file_exists("custom/include/language/{$language}.notify_template.html")){
443 $file = "custom/include/language/{$language}.notify_template.html";
445 else if(file_exists("include/language/{$language}.notify_template.html")){
446 $file = "include/language/{$language}.notify_template.html";
448 else if(file_exists("custom/include/language/en_us.notify_template.html")){
449 $file = "custom/include/language/en_us.notify_template.html";
455 function sugar_config_union( $default, $override ){
456 // a little different then array_merge and array_merge_recursive. we want
457 // the second array to override the first array if the same value exists,
458 // otherwise merge the unique keys. it handles arrays of arrays recursively
459 // might be suitable for a generic array_union
460 if( !is_array( $override ) ){
463 foreach( $default as $key => $value ){
464 if( !array_key_exists($key, $override) ){
465 $override[$key] = $value;
467 else if( is_array( $key ) ){
468 $override[$key] = sugar_config_union( $value, $override[$key] );
474 function make_not_writable( $file ){
475 // Returns true if the given file/dir has been made not writable
477 if( is_file($file) || is_dir($file) ){
478 if( !is_writable($file) ){
482 $original_fileperms = fileperms($file);
484 // take away writable permissions
485 $new_fileperms = $original_fileperms & ~0x0092;
486 @sugar_chmod($file, $new_fileperms);
488 if( !is_writable($file) ){
497 /** This function returns the name of the person.
498 * It currently returns "first last". It should not put the space if either name is not available.
499 * It should not return errors if either name is not available.
500 * If no names are present, it will return ""
501 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
502 * All Rights Reserved.
503 * Contributor(s): ______________________________________..
505 function return_name($row, $first_column, $last_column)
511 if(isset($row[$first_column]))
513 $first_name = stripslashes($row[$first_column]);
516 if(isset($row[$last_column]))
518 $last_name = stripslashes($row[$last_column]);
521 $full_name = $first_name;
523 // If we have a first name and we have a last name
524 if($full_name != "" && $last_name != "")
526 // append a space, then the last name
527 $full_name .= " ".$last_name;
529 // If we have no first name, but we have a last name
530 else if($last_name != "")
532 // append the last name without the space.
533 $full_name .= $last_name;
540 function get_languages()
542 global $sugar_config;
543 $lang = $sugar_config['languages'];
544 if(!empty($sugar_config['disabled_languages'])){
545 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
546 unset($lang[$disable]);
552 function get_all_languages()
554 global $sugar_config;
555 return $sugar_config['languages'];
559 function get_language_display($key)
561 global $sugar_config;
562 return $sugar_config['languages'][$key];
565 function get_assigned_user_name($assigned_user_id, $is_group = '') {
566 static $saved_user_list = null;
568 if(empty($saved_user_list)) {
569 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
572 if(isset($saved_user_list[$assigned_user_id])) {
573 return $saved_user_list[$assigned_user_id];
580 * retrieves the user_name column value (login)
581 * @param string id GUID of user
584 function get_user_name($id) {
588 $db = DBManagerFactory::getInstance();
590 $q = "SELECT user_name FROM users WHERE id='{$id}'";
592 $a = $db->fetchByAssoc($r);
594 return (empty($a)) ? '' : $a['user_name'];
598 //TODO Update to use global cache
602 * This is a helper function to return an Array of users depending on the parameters passed into the function.
603 * This function uses the get_register_value function by default to use a caching layer where supported.
605 * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
606 * @param string $status String value indicating the status to filter users by, "Active" by default
607 * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
608 * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
609 * @param String $user_name_filter String value indicating the user_name filter (searches the user_name column of users table) to optionally search with, blank by default
610 * @param string $portal_filter String query filter for portal users (defaults to searching non-portal users), change to blank if you wish to search for all users including portal users
611 * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
612 * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
614 function get_user_array($add_blank=true, $status="Active", $user_id='', $use_real_name=false, $user_name_filter='', $portal_filter=' AND portal_only=0 ', $from_cache = true) {
616 global $sugar_config;
619 $locale = new Localization();
623 $key_name = $add_blank. $status . $user_id . $use_real_name . $user_name_filter . $portal_filter;
624 $user_array = get_register_value('user_array', $key_name);
627 if(empty($user_array)) {
628 $db = DBManagerFactory::getInstance();
629 $temp_result = Array();
630 // Including deleted users for now.
631 if (empty($status)) {
632 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$portal_filter;
635 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
638 if (!empty($user_name_filter)) {
639 $user_name_filter = $db->quote($user_name_filter);
640 $query .= " AND user_name LIKE '$user_name_filter%' ";
642 if (!empty($user_id)) {
643 $query .= " OR id='{$user_id}'";
645 $query = $query.' ORDER BY user_name ASC';
646 $GLOBALS['log']->debug("get_user_array query: $query");
647 $result = $db->query($query, true, "Error filling in user array: ");
649 if ($add_blank==true) {
650 // Add in a blank row
651 $temp_result[''] = '';
654 // Get the id and the name.
655 while($row = $db->fetchByAssoc($result)) {
656 if($use_real_name == true || showFullName()) {
657 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
658 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
660 $temp_result[$row['id']] = $row['user_name'];
663 $temp_result[$row['id']] = $row['user_name'];
667 $user_array = $temp_result;
670 set_register_value('user_array', $key_name, $temp_result);
680 * uses a different query to return a list of users than get_user_array()
681 * Used from QuickSearch.php
682 * @param args string where clause entry
683 * @return array Array of Users' details that match passed criteria
685 function getUserArrayFromFullName($args, $hide_portal_users = false) {
687 $db = DBManagerFactory::getInstance();
690 if(strpos($args, " ")) {
691 $argArray = explode(" ", $args);
697 foreach($argArray as $arg) {
698 if(!empty($inClause)) {
703 $arg = $db->quote($arg);
704 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
707 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
708 if ( $hide_portal_users ) {
709 $query .= " portal_only=0 AND ";
712 $query .= " ORDER BY last_name ASC";
714 $r = $db->query($query);
716 while($a = $db->fetchByAssoc($r)) {
717 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
725 * based on user pref then system pref
727 function showFullName() {
728 global $sugar_config;
729 global $current_user;
730 static $showFullName = null;
732 if (is_null($showFullName)) {
733 $sysPref = !empty($sugar_config['use_real_names']);
734 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
736 if($userPref != null) {
737 $showFullName = ($userPref == 'on');
739 $showFullName = $sysPref;
743 return $showFullName;
746 function clean($string, $maxLength)
748 $string = substr($string, 0, $maxLength);
749 return escapeshellcmd($string);
753 * Copy the specified request variable to the member variable of the specified object.
754 * Do no copy if the member variable is already set.
755 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
756 * All Rights Reserved.
757 * Contributor(s): ______________________________________..
759 function safe_map($request_var, & $focus, $always_copy = false)
761 safe_map_named($request_var, $focus, $request_var, $always_copy);
765 * Copy the specified request variable to the member variable of the specified object.
766 * Do no copy if the member variable is already set.
767 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
768 * All Rights Reserved.
769 * Contributor(s): ______________________________________..
771 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
773 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
774 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
775 $focus->$member_var = $_REQUEST[$request_var];
780 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
782 * @param string $language specific language to load
783 * @return array lang strings
785 function return_app_list_strings_language($language)
787 global $app_list_strings;
788 global $sugar_config;
790 $cache_key = 'app_list_strings.'.$language;
792 // Check for cached value
793 $cache_entry = sugar_cache_retrieve($cache_key);
794 if(!empty($cache_entry))
799 $default_language = $sugar_config['default_language'];
800 $temp_app_list_strings = $app_list_strings;
803 if ($language != 'en_us') {
806 if ($default_language != 'en_us' && $language != $default_language) {
807 $langs[] = $default_language;
809 $langs[] = $language;
811 $app_list_strings_array = array();
813 foreach ( $langs as $lang ) {
814 $app_list_strings = array();
815 if(file_exists("include/language/$lang.lang.php")) {
816 include("include/language/$lang.lang.php");
817 $GLOBALS['log']->info("Found language file: $lang.lang.php");
819 if(file_exists("include/language/$lang.lang.override.php")) {
820 include("include/language/$lang.lang.override.php");
821 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
823 if(file_exists("include/language/$lang.lang.php.override")) {
824 include("include/language/$lang.lang.php.override");
825 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
828 $app_list_strings_array[] = $app_list_strings;
831 $app_list_strings = array();
832 foreach ( $app_list_strings_array as $app_list_strings_item ) {
833 $app_list_strings = sugarLangArrayMerge($app_list_strings, $app_list_strings_item);
836 foreach ( $langs as $lang ) {
837 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
838 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
839 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
841 if(file_exists("custom/include/language/$lang.lang.php")) {
842 include("custom/include/language/$lang.lang.php");
843 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
847 if(!isset($app_list_strings)) {
848 $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");
852 $return_value = $app_list_strings;
853 $app_list_strings = $temp_app_list_strings;
855 sugar_cache_put($cache_key, $return_value);
857 return $return_value;
861 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
862 * $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.
863 * @param file string the language that you want include,
864 * @param app_list_strings array the golbal strings
868 function _mergeCustomAppListStrings($file , $app_list_strings){
869 $app_list_strings_original = $app_list_strings;
870 unset($app_list_strings);
871 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
872 // This way, language file can add items to save specific standard codelist from being overwritten
873 $exemptDropdowns = array();
875 if(!isset($app_list_strings) || !is_array($app_list_strings)){
876 return $app_list_strings_original;
878 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
880 // FG - bug 45525 - Specific codelists must NOT be overwritten
881 $exemptDropdowns[] = "moduleList";
882 $exemptDropdowns[] = "parent_type_display";
883 $exemptDropdowns[] = "record_type_display";
884 $exemptDropdowns[] = "record_type_display_notes";
886 foreach($app_list_strings as $key=>$value)
888 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
890 unset($app_list_strings_original["$key"]);
893 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
894 return $app_list_strings;
898 * This function retrieves an application language file and returns the array of strings included.
900 * @param string $language specific language to load
901 * @return array lang strings
903 function return_application_language($language)
905 global $app_strings, $sugar_config;
907 $cache_key = 'app_strings.'.$language;
909 // Check for cached value
910 $cache_entry = sugar_cache_retrieve($cache_key);
911 if(!empty($cache_entry))
916 $temp_app_strings = $app_strings;
917 $default_language = $sugar_config['default_language'];
920 if ($language != 'en_us') {
923 if ($default_language != 'en_us' && $language != $default_language) {
924 $langs[] = $default_language;
927 $langs[] = $language;
929 $app_strings_array = array();
931 foreach ( $langs as $lang ) {
932 $app_strings = array();
933 if(file_exists("include/language/$lang.lang.php")) {
934 include("include/language/$lang.lang.php");
935 $GLOBALS['log']->info("Found language file: $lang.lang.php");
937 if(file_exists("include/language/$lang.lang.override.php")) {
938 include("include/language/$lang.lang.override.php");
939 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
941 if(file_exists("include/language/$lang.lang.php.override")) {
942 include("include/language/$lang.lang.php.override");
943 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
945 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
946 include("custom/application/Ext/Language/$lang.lang.ext.php");
947 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
949 if(file_exists("custom/include/language/$lang.lang.php")) {
950 include("custom/include/language/$lang.lang.php");
951 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
953 $app_strings_array[] = $app_strings;
956 $app_strings = array();
957 foreach ( $app_strings_array as $app_strings_item ) {
958 $app_strings = sugarLangArrayMerge($app_strings, $app_strings_item);
961 if(!isset($app_strings)) {
962 $GLOBALS['log']->fatal("Unable to load the application language strings");
966 // If we are in debug mode for translating, turn on the prefix now!
967 if($sugar_config['translation_string_prefix']) {
968 foreach($app_strings as $entry_key=>$entry_value) {
969 $app_strings[$entry_key] = $language.' '.$entry_value;
972 if(isset($_SESSION['show_deleted'])) {
973 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
974 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
975 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
976 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
979 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
981 $return_value = $app_strings;
982 $app_strings = $temp_app_strings;
984 sugar_cache_put($cache_key, $return_value);
986 return $return_value;
990 * This function retrieves a module's language file and returns the array of strings included.
992 * @param string $language specific language to load
993 * @param string $module module name to load strings for
994 * @param bool $refresh optional, true if you want to rebuild the language strings
995 * @return array lang strings
997 function return_module_language($language, $module, $refresh=false)
1000 global $sugar_config;
1001 global $currentModule;
1003 // Jenny - Bug 8119: Need to check if $module is not empty
1004 if (empty($module)) {
1005 $stack = debug_backtrace();
1006 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
1012 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1013 // Check for cached value
1014 $cache_entry = sugar_cache_retrieve($cache_key);
1015 if(!empty($cache_entry))
1017 return $cache_entry;
1020 // Store the current mod strings for later
1021 $temp_mod_strings = $mod_strings;
1022 $loaded_mod_strings = array();
1023 $language_used = $language;
1024 $default_language = $sugar_config['default_language'];
1026 if(empty($language)) {
1027 $language = $default_language;
1030 // Bug 21559 - So we can get all the strings defined in the template, refresh
1031 // the vardefs file if the cached language file doesn't exist.
1032 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1033 && !empty($GLOBALS['beanList'][$module])){
1034 $object = BeanFactory::getObjectName($module);
1035 VardefManager::refreshVardefs($module,$object);
1038 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1040 // cn: bug 6048 - merge en_us with requested language
1041 if($language != $sugar_config['default_language'])
1042 $loaded_mod_strings = sugarLangArrayMerge(
1043 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1047 // Load in en_us strings by default
1048 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1049 $loaded_mod_strings = sugarLangArrayMerge(
1050 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1054 // If we are in debug mode for translating, turn on the prefix now!
1055 if($sugar_config['translation_string_prefix']) {
1056 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1057 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1061 $return_value = $loaded_mod_strings;
1062 if(!isset($mod_strings)){
1063 $mod_strings = $return_value;
1066 $mod_strings = $temp_mod_strings;
1068 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1069 sugar_cache_put($cache_key, $return_value);
1070 return $return_value;
1074 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1075 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1076 * All Rights Reserved.
1077 * Contributor(s): ______________________________________..
1078 * If you are using the current language, do not call this function unless you are loading it for the first time */
1079 function return_mod_list_strings_language($language,$module) {
1080 global $mod_list_strings;
1081 global $sugar_config;
1082 global $currentModule;
1084 $cache_key = "mod_list_str_lang.".$language.$module;
1086 // Check for cached value
1087 $cache_entry = sugar_cache_retrieve($cache_key);
1088 if(!empty($cache_entry))
1090 return $cache_entry;
1093 $language_used = $language;
1094 $temp_mod_list_strings = $mod_list_strings;
1095 $default_language = $sugar_config['default_language'];
1097 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1098 return $mod_list_strings;
1101 // cn: bug 6351 - include en_us if file langpack not available
1102 // cn: bug 6048 - merge en_us with requested language
1103 include("modules/$module/language/en_us.lang.php");
1104 $en_mod_list_strings = array();
1105 if($language_used != $default_language)
1106 $en_mod_list_strings = $mod_list_strings;
1108 if(file_exists("modules/$module/language/$language.lang.php")) {
1109 include("modules/$module/language/$language.lang.php");
1112 if(file_exists("modules/$module/language/$language.lang.override.php")){
1113 include("modules/$module/language/$language.lang.override.php");
1116 if(file_exists("modules/$module/language/$language.lang.php.override")){
1117 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1118 include("modules/$module/language/$language.lang.php.override");
1121 // cn: bug 6048 - merge en_us with requested language
1122 $mod_list_strings = sugarLangArrayMerge($en_mod_list_strings, $mod_list_strings);
1124 // if we still don't have a language pack, then log an error
1125 if(!isset($mod_list_strings)) {
1126 $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})");
1130 $return_value = $mod_list_strings;
1131 $mod_list_strings = $temp_mod_list_strings;
1133 sugar_cache_put($cache_key, $return_value);
1134 return $return_value;
1138 /** This function retrieves a theme's language file and returns the array of strings included.
1139 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1140 * All Rights Reserved.
1141 * Contributor(s): ______________________________________..
1143 function return_theme_language($language, $theme)
1145 global $mod_strings, $sugar_config, $current_language;
1147 $language_used = $language;
1148 $default_language = $sugar_config['default_language'];
1150 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1151 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1152 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1154 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1155 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";
1156 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1158 if(!isset($theme_strings))
1160 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1161 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1162 $language_used = $default_language;
1165 if(!isset($theme_strings))
1167 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1171 // If we are in debug mode for translating, turn on the prefix now!
1172 if($sugar_config['translation_string_prefix'])
1174 foreach($theme_strings as $entry_key=>$entry_value)
1176 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1180 return $theme_strings;
1185 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1186 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1187 * All Rights Reserved.
1188 * Contributor(s): ______________________________________..
1190 function return_session_value_or_default($varname, $default)
1192 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1194 return $_SESSION[$varname];
1201 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1202 * 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.
1203 * @param &$where_clauses - The array to append the clause to
1204 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1205 * @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.
1206 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1207 * All Rights Reserved.
1208 * Contributor(s): ______________________________________..
1210 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1212 if($SQL_name == null)
1214 $SQL_name = $variable_name;
1217 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1219 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1224 * Generate the appropriate SQL based on the where clauses.
1225 * @param $where_clauses - An Array of individual where clauses stored as strings
1226 * @returns string where_clause - The final SQL where clause to be executed.
1227 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1228 * All Rights Reserved.
1229 * Contributor(s): ______________________________________..
1231 function generate_where_statement($where_clauses)
1234 foreach($where_clauses as $clause)
1241 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1246 * determines if a passed string matches the criteria for a Sugar GUID
1247 * @param string $guid
1248 * @return bool False on failure
1250 function is_guid($guid) {
1251 if(strlen($guid) != 36) {
1255 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1264 * A temporary method of generating GUIDs of the correct format for our DB.
1265 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1267 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1268 * All Rights Reserved.
1269 * Contributor(s): ______________________________________..
1271 function create_guid()
1273 $microTime = microtime();
1274 list($a_dec, $a_sec) = explode(" ", $microTime);
1276 $dec_hex = dechex($a_dec* 1000000);
1277 $sec_hex = dechex($a_sec);
1279 ensure_length($dec_hex, 5);
1280 ensure_length($sec_hex, 6);
1284 $guid .= create_guid_section(3);
1286 $guid .= create_guid_section(4);
1288 $guid .= create_guid_section(4);
1290 $guid .= create_guid_section(4);
1293 $guid .= create_guid_section(6);
1299 function create_guid_section($characters)
1302 for($i=0; $i<$characters; $i++)
1304 $return .= dechex(mt_rand(0,15));
1309 function ensure_length(&$string, $length)
1311 $strlen = strlen($string);
1312 if($strlen < $length)
1314 $string = str_pad($string,$length,"0");
1316 else if($strlen > $length)
1318 $string = substr($string, 0, $length);
1322 function microtime_diff($a, $b) {
1323 list($a_dec, $a_sec) = explode(" ", $a);
1324 list($b_dec, $b_sec) = explode(" ", $b);
1325 return $b_sec - $a_sec + $b_dec - $a_dec;
1328 // check if Studio is displayed.
1329 function displayStudioForCurrentUser()
1331 global $current_user;
1332 if ( $current_user->isAdmin() ) {
1342 function displayWorkflowForCurrentUser()
1344 $_SESSION['display_workflow_for_user'] = false;
1348 // return an array with all modules where the user is an admin.
1349 function get_admin_modules_for_user($user) {
1350 $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");
1357 return($user->getDeveloperModules());
1361 function get_workflow_admin_modules_for_user($user){
1362 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1363 return $_SESSION['get_workflow_admin_modules_for_user'];
1367 $workflow_mod_list = array();
1368 foreach($moduleList as $module){
1369 $workflow_mod_list[$module] = $module;
1372 // This list is taken from teh previous version of workflow_utils.php
1373 $workflow_mod_list['Tasks'] = "Tasks";
1374 $workflow_mod_list['Calls'] = "Calls";
1375 $workflow_mod_list['Meetings'] = "Meetings";
1376 $workflow_mod_list['Notes'] = "Notes";
1377 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1378 $workflow_mod_list['Leads'] = "Leads";
1379 $workflow_mod_list['Opportunities'] = "Opportunities";
1382 $workflow_admin_modules = array();
1384 return $workflow_admin_modules;
1386 $actions = ACLAction::getUserActions($user->id);
1387 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1388 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1389 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1390 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1392 foreach ($workflow_mod_list as $key=>$val) {
1393 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1394 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1395 ($user->isDeveloperForModule($key))) {
1396 $workflow_admin_modules[$key] = $val;
1399 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1400 return ($workflow_admin_modules);
1403 // Check if user is admin for at least one module.
1404 function is_admin_for_any_module($user) {
1408 if($user->isAdmin()) {
1415 // Check if user is admin for a specific module.
1416 function is_admin_for_module($user,$module) {
1417 if (!isset($user)) {
1420 if ($user->isAdmin()) {
1428 * Check if user id belongs to a system admin.
1429 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1430 * All Rights Reserved.
1431 * Contributor(s): ______________________________________..
1433 function is_admin($user) {
1438 return $user->isAdmin();
1442 * Return the display name for a theme if it exists.
1443 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1444 * All Rights Reserved.
1445 * Contributor(s): ______________________________________..
1447 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1449 function get_theme_display($theme)
1451 return SugarThemeRegistry::get($theme)->name;
1455 * Return an array of directory names.
1456 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1457 * All Rights Reserved.
1458 * Contributor(s): ______________________________________..
1460 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1462 function get_themes()
1464 return SugarThemeRegistry::availableThemes();
1468 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1469 * Create HTML to display select options in a dropdown list. To be used inside
1470 * of a select statement in a form.
1471 * param $option_list - the array of strings to that contains the option list
1472 * param $selected - the string which contains the default value
1473 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1474 * All Rights Reserved.
1475 * Contributor(s): ______________________________________..
1477 function get_select_options ($option_list, $selected) {
1478 return get_select_options_with_id($option_list, $selected);
1482 * Create HTML to display select options in a dropdown list. To be used inside
1483 * 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.
1484 * param $option_list - the array of strings to that contains the option list
1485 * param $selected - the string which contains the default value
1486 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1487 * All Rights Reserved.
1488 * Contributor(s): ______________________________________..
1490 function get_select_options_with_id ($option_list, $selected_key) {
1491 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1496 * Create HTML to display select options in a dropdown list. To be used inside
1497 * 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.
1498 * param $label_list - the array of strings to that contains the option list
1499 * param $key_list - the array of strings to that contains the values list
1500 * param $selected - the string which contains the default value
1501 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1502 * All Rights Reserved.
1503 * Contributor(s): ______________________________________..
1505 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1506 global $app_strings;
1507 $select_options = "";
1509 //for setting null selection values to human readable --None--
1510 $pattern = "/'0?'></";
1511 $replacement = "''>".$app_strings['LBL_NONE']."<";
1513 $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
1516 if (empty($key_list)) $key_list = array();
1517 //create the type dropdown domain and set the selected value if $opp value already exists
1518 foreach ($key_list as $option_key=>$option_value) {
1520 $selected_string = '';
1521 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1522 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1523 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1525 $selected_string = 'selected ';
1528 $html_value = $option_key;
1530 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1532 $select_options = preg_replace($pattern, $replacement, $select_options);
1533 return $select_options;
1538 * Call this method instead of die().
1539 * Then we call the die method with the error message that is passed in.
1541 function sugar_die($error_message)
1545 die($error_message);
1550 * Create javascript to clear values of all elements in a form.
1551 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1552 * All Rights Reserved.
1553 * Contributor(s): ______________________________________..
1555 function get_clear_form_js () {
1556 $the_script = <<<EOQ
1557 <script type="text/javascript" language="JavaScript">
1558 function clear_form(form) {
1559 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1560 if(typeof(form.advanced) != 'undefined'){
1561 newLoc += '&advanced=' + form.advanced.value;
1563 document.location.href= newLoc;
1572 * Create javascript to set the cursor focus to specific field in a form
1573 * when the screen is rendered. The field name is currently hardcoded into the
1575 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1576 * All Rights Reserved.
1577 * Contributor(s): ______________________________________..
1579 function get_set_focus_js () {
1580 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1581 $the_script = <<<EOQ
1582 <script type="text/javascript" language="JavaScript">
1584 function set_focus() {
1585 if (document.forms.length > 0) {
1586 for (i = 0; i < document.forms.length; i++) {
1587 for (j = 0; j < document.forms[i].elements.length; j++) {
1588 var field = document.forms[i].elements[j];
1589 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1590 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1592 if (field.type == "text") {
1609 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1610 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1611 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1612 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1613 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1614 * the first - so the array is sorted by the last given column first, then the one before ...
1615 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1616 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1617 * All Rights Reserved.
1618 * Contributor(s): ______________________________________..
1620 function array_csort() {
1621 $args = func_get_args();
1622 $marray = array_shift($args);
1625 $msortline = "return(array_multisort(";
1626 foreach ($args as $arg) {
1628 if (is_string($arg)) {
1629 foreach ($marray as $row) {
1630 $sortarr[$i][] = $row[$arg];
1633 $sortarr[$i] = $arg;
1635 $msortline .= "\$sortarr[".$i."],";
1637 $msortline .= "\$marray));";
1644 * Converts localized date format string to jscalendar format
1645 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1646 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1647 * All Rights Reserved.
1648 * Contributor(s): ______________________________________..
1650 function parse_calendardate($local_format) {
1651 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1652 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1653 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1660 function translate($string, $mod='', $selectedValue=''){
1661 //$test_start = microtime();
1662 //static $mod_strings_results = array();
1664 global $current_language;
1666 if(isset($_REQUEST['login_language'])){
1667 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1669 $mod_strings = return_module_language($current_language, $mod);
1672 global $mod_strings;
1676 global $app_strings, $app_list_strings;
1678 if(isset($mod_strings[$string]))
1679 $returnValue = $mod_strings[$string];
1680 else if(isset($app_strings[$string]))
1681 $returnValue = $app_strings[$string];
1682 else if(isset($app_list_strings[$string]))
1683 $returnValue = $app_list_strings[$string];
1684 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1685 $returnValue = $app_list_strings['moduleList'][$string];
1688 //$test_end = microtime();
1690 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1692 // echo("translate results:");
1694 // $total_strings = 0;
1695 // foreach($mod_strings_results as $key=>$value)
1697 // echo("Module $key \t\t time $value \t\t<br>");
1698 // $total_time += $value;
1701 // echo("Total time: $total_time<br>");
1705 if(empty($returnValue)){
1709 if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1710 return $returnValue[$selectedValue];
1713 return $returnValue;
1716 function unTranslateNum($num) {
1718 static $num_grp_sep;
1719 global $current_user, $sugar_config;
1721 if($dec_sep == null) {
1722 $user_dec_sep = $current_user->getPreference('dec_sep');
1723 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1725 if($num_grp_sep == null) {
1726 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1727 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1730 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1731 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1736 function add_http($url) {
1737 if(!preg_match("@://@i", $url)) {
1739 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1743 return "{$scheme}://{$url}";
1750 * returns a default array of XSS tags to clean
1753 function getDefaultXssTags() {
1755 "applet" => "applet",
1760 "frameset" => "frameset",
1761 "iframe" => "iframe",
1762 "import" => "\?import",
1765 "object" => "object",
1766 "script" => "script",
1770 $ret = base64_encode(serialize($tmp));
1776 * Remove potential xss vectors from strings
1777 * @param string str String to search for XSS attack vectors
1781 function remove_xss($str)
1783 return SugarCleaner::cleanHtml($str, false);
1787 * Detects typical XSS attack patterns
1789 * @param string str String to search for XSS attack vectors
1790 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1791 * @return array Array of matches, empty on clean string
1793 function clean_xss($str, $cleanImg=true) {
1794 global $sugar_config;
1796 if(empty($sugar_config['email_xss']))
1797 $sugar_config['email_xss'] = getDefaultXssTags();
1799 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1801 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1802 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1803 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1804 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1806 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1807 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1808 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1809 $css_url = '#url\(.*\.\w+\)#';
1811 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1813 $tagmatches = array();
1815 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1816 foreach($tagmatches[1] as $no => $tag) {
1817 if(in_array($tag, $xsstags)) {
1818 // dangerous tag - take out whole
1819 $matches[] = $tagmatches[0][$no];
1822 $attrmatch = array();
1823 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1824 if(!empty($attrmatch[0])) {
1825 $matches = array_merge($matches, $attrmatch[0]);
1829 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1832 $matches = array_merge($matches,
1833 xss_check_pattern($imgsrc_regex, $str)
1837 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1838 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1840 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1841 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1842 // normalize whitelist
1843 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1844 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1847 foreach($cssUrlMatches[0] as $match) {
1848 $domain = strtolower(substr(strstr($match, "://"), 3));
1849 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1851 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1852 $matches[] = $match;
1857 $matches = array_merge($matches, $cssUrlMatches[0]);
1864 * Helper function used by clean_xss() to parse for known-bad vectors
1865 * @param string pattern Regex pattern to use
1866 * @param string str String to parse for badness
1869 function xss_check_pattern($pattern, $str) {
1870 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1875 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1877 * @param string $str
1878 * @param string $filter which corresponds to a regular expression to use; choices are:
1879 * "STANDARD" ( default )
1889 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1891 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1893 global $sugar_config;
1896 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1897 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1898 "FILE" => '#[^A-Z0-9\-_\.]#i',
1899 "NUMBER" => '#[^0-9\-]#i',
1900 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1901 "PATH_NO_URL" => '#://#i',
1902 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1903 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1904 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1905 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1908 if (preg_match($filters[$filter], $str)) {
1909 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1910 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1912 if ( $dieOnBadData ) {
1913 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1922 function clean_special_arguments() {
1923 if(isset($_SERVER['PHP_SELF'])) {
1924 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1926 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1927 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1928 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1929 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1930 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1931 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1932 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1933 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1934 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1935 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1936 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1937 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1938 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1939 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1940 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1941 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1942 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1943 clean_superglobals('offset', 'ALPHANUM');
1944 clean_superglobals('return_action');
1945 clean_superglobals('return_module');
1950 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1952 function clean_superglobals($key, $filter = 'STANDARD') {
1953 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1954 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1955 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1958 function set_superglobals($key, $val){
1960 $_POST[$key] = $val;
1961 $_REQUEST[$key] = $val;
1964 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1965 function clean_incoming_data() {
1966 global $sugar_config;
1967 global $RAW_REQUEST;
1969 if(get_magic_quotes_gpc()) {
1970 // magic quotes screw up data, we'd have to clean up
1971 $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1973 $RAW_REQUEST = $_REQUEST;
1976 if (get_magic_quotes_gpc() == 1) {
1977 $req = array_map("preprocess_param", $_REQUEST);
1978 $post = array_map("preprocess_param", $_POST);
1979 $get = array_map("preprocess_param", $_GET);
1982 $req = array_map("securexss", $_REQUEST);
1983 $post = array_map("securexss", $_POST);
1984 $get = array_map("securexss", $_GET);
1987 // PHP cannot stomp out superglobals reliably
1988 foreach($post as $k => $v) { $_POST[$k] = $v; }
1989 foreach($get as $k => $v) { $_GET[$k] = $v; }
1990 foreach($req as $k => $v) {
1992 //ensure the keys are safe as well
1995 // Any additional variables that need to be cleaned should be added here
1996 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1997 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1998 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1999 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
2000 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
2001 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
2002 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
2003 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
2004 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
2005 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
2006 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
2007 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
2008 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
2010 if(isset($_REQUEST['lvso'])){
2011 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
2013 // Clean "offset" and "order_by" parameters in URL
2014 foreach ($_REQUEST as $key => $val) {
2015 if (str_end($key, "_offset")) {
2016 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
2017 set_superglobals($key, $_REQUEST[$key]);
2019 elseif (str_end($key, "_ORDER_BY")) {
2020 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2021 set_superglobals($key, $_REQUEST[$key]);
2029 // Returns TRUE if $str begins with $begin
2030 function str_begin($str, $begin) {
2031 return (substr($str, 0, strlen($begin)) == $begin);
2034 // Returns TRUE if $str ends with $end
2035 function str_end($str, $end) {
2036 return (substr($str, strlen($str) - strlen($end)) == $end);
2039 function securexss($value) {
2040 if(is_array($value)){
2042 foreach($value as $key=>$val){
2043 $new[$key] = securexss($val);
2047 static $xss_cleanup= array(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2048 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2049 $value = preg_replace('/javascript:/i', 'java script:', $value);
2050 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2053 function securexsskey($value, $die=true){
2054 global $sugar_config;
2056 preg_match('/[\'"<>]/', $value, $matches);
2057 if(!empty($matches)){
2059 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2061 unset($_REQUEST[$value]);
2062 unset($_POST[$value]);
2063 unset($_GET[$value]);
2068 function preprocess_param($value){
2069 if(is_string($value)){
2070 if(get_magic_quotes_gpc() == 1){
2071 $value = stripslashes($value);
2074 $value = securexss($value);
2080 function cleanup_slashes($value)
2082 if(is_string($value)) return stripslashes($value);
2087 function set_register_value($category, $name, $value){
2088 return sugar_cache_put("{$category}:{$name}", $value);
2091 function get_register_value($category,$name){
2092 return sugar_cache_retrieve("{$category}:{$name}");
2095 function clear_register_value($category,$name){
2096 return sugar_cache_clear("{$category}:{$name}");
2098 // this function cleans id's when being imported
2099 function convert_id($string)
2101 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2103 // single quotes are essential here,
2104 // or alternative escape all $ as \$
2106 'return ord($matches[0]);'
2111 * @deprecated use SugarTheme::getImage()
2113 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2115 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2118 * @deprecated use SugarTheme::getImageURL()
2120 function getImagePath($image_name)
2122 return SugarThemeRegistry::current()->getImageURL($image_name);
2125 function getWebPath($relative_path){
2126 //if it has a :// then it isn't a relative path
2127 if(substr_count($relative_path, '://') > 0) return $relative_path;
2128 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2129 return $relative_path;
2132 function getVersionedPath($path, $additional_attrs='')
2134 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2135 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2136 if(inDeveloperMode()) {
2138 if(empty($rand)) $rand = mt_rand();
2143 if(is_array($additional_attrs)) {
2144 $additional_attrs = join("|",$additional_attrs);
2146 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2147 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2148 // remove / - it confuses some parsers
2149 $str = strtr($str, '/+', '-_');
2150 if(empty($path)) return $str;
2152 return $path . "?v=$str";
2155 function getVersionedScript($path, $additional_attrs='')
2157 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2160 function getJSPath($relative_path, $additional_attrs='')
2162 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2163 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2166 function getSWFPath($relative_path, $additional_params=''){
2167 $path = $relative_path;
2168 if (!empty($additional_params)){
2169 $path .= '?' . $additional_params;
2171 if (defined('TEMPLATE_URL')){
2172 $path = TEMPLATE_URL . '/' . $path;
2181 function getSQLDate($date_str)
2183 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2185 if ( strlen($match[2]) == 1)
2187 $match[2] = "0".$match[2];
2189 if ( strlen($match[1]) == 1)
2191 $match[1] = "0".$match[1];
2193 return "{$match[3]}-{$match[1]}-{$match[2]}";
2195 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2197 if ( strlen($match[2]) == 1)
2199 $match[2] = "0".$match[2];
2201 if ( strlen($match[1]) == 1)
2203 $match[1] = "0".$match[1];
2205 return "{$match[3]}-{$match[1]}-{$match[2]}";
2213 function clone_history(&$db, $from_id,$to_id, $to_type)
2218 require_once('include/upload_file.php');
2219 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2221 $location=array('Email'=>"modules/Emails/Email.php",
2222 'Call'=>"modules/Calls/Call.php",
2223 'Meeting'=>"modules/Meetings/Meeting.php",
2224 'Note'=>"modules/Notes/Note.php",
2225 'Tasks'=>"modules/Tasks/Task.php",
2229 foreach($tables as $table=>$bean_class)
2232 if (!class_exists($bean_class))
2234 require_once($location[$bean_class]);
2237 $bProcessingNotes=false;
2238 if ($table=='notes')
2240 $bProcessingNotes=true;
2242 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2243 $results = $db->query($query);
2244 while($row = $db->fetchByAssoc($results))
2246 //retrieve existing record.
2247 $bean= new $bean_class();
2248 $bean->retrieve($row['id']);
2249 //process for new instance.
2250 if ($bProcessingNotes)
2252 $old_note_id=$row['id'];
2253 $old_filename=$bean->filename;
2256 $bean->parent_id=$to_id;
2257 $bean->parent_type=$to_type;
2258 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2260 $bean->contact_id=$to_id;
2262 $bean->update_date_modified = false;
2263 $bean->update_modified_by = false;
2264 if(isset($bean->date_modified))
2265 $bean->date_modified = $timedate->to_db($bean->date_modified);
2266 if(isset($bean->date_entered))
2267 $bean->date_entered = $timedate->to_db($bean->date_entered);
2269 $new_id=$bean->save();
2271 //duplicate the file now. for notes.
2272 if ($bProcessingNotes && !empty($old_filename))
2274 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2276 //reset the values needed for attachment duplication.
2283 function values_to_keys($array)
2285 $new_array = array();
2286 if(!is_array($array))
2290 foreach($array as $arr){
2291 $new_array[$arr] = $arr;
2296 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2298 foreach($tables as $table)
2301 if ($table == 'emails_beans') {
2302 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2304 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2306 $results = $db->query($query);
2307 while($row = $db->fetchByAssoc($results))
2309 $query = "INSERT INTO $table ";
2312 $row[$from_column] = $to_id;
2313 $row['id'] = create_guid();
2314 if ($table=='emails_beans') {
2315 $row['bean_module'] =='Contacts';
2318 foreach($row as $name=>$value)
2324 $values .= "'$value'";
2327 $names .= ', '. $name;
2328 $values .= ", '$value'";
2331 $query .= "($names) VALUES ($values)";
2337 function get_unlinked_email_query($type, $bean) {
2338 global $current_user;
2340 $return_array['select']='SELECT emails.id ';
2341 $return_array['from']='FROM emails ';
2342 $return_array['where']="";
2343 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2345 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2346 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2347 where eear.deleted=0 and eear.email_id not in
2348 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2349 ) derivedemails on derivedemails.email_id = emails.id";
2350 $return_array['join_tables'][0] = '';
2352 if (isset($type) and !empty($type['return_as_array'])) {
2353 return $return_array;
2356 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2359 function get_emails_by_assign_or_link($params)
2361 $relation = $params['link'];
2362 $bean = $GLOBALS['app']->controller->bean;
2363 if(empty($bean->$relation)) {
2364 $bean->load_relationship($relation);
2366 if(empty($bean->$relation)) {
2367 $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
2370 $rel_module = $bean->$relation->getRelatedModuleName();
2371 $rel_join = $bean->$relation->getJoin(array(
2372 'join_table_alias' => 'link_bean',
2373 'join_table_link_alias' => 'linkt',
2375 $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
2376 $return_array['select']='SELECT emails.id ';
2377 $return_array['from'] = "FROM emails ";
2378 $return_array['join'] = " INNER JOIN (".
2379 // directly assigned emails
2380 "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 ".
2382 // Assigned to contacts
2383 "select DISTINCT eb.email_id FROM emails_beans eb
2384 $rel_join AND link_bean.id = eb.bean_id
2385 where eb.bean_module = '$rel_module' AND eb.deleted=0".
2387 // Related by directly by email
2388 "select DISTINCT eear.email_id from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2389 ON eabr.bean_id ='{$bean->id}' AND eabr.bean_module = '{$bean->module_dir}' AND
2390 eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0".
2392 // Related by email to linked contact
2393 "select DISTINCT eear.email_id FROM emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2394 ON eabr.email_address_id=eear.email_address_id AND eabr.bean_module = '$rel_module' AND eabr.deleted=0
2395 $rel_join AND link_bean.id = eabr.bean_id
2396 where eear.deleted=0".
2397 ") email_ids ON emails.id=email_ids.email_id ";
2398 $return_array['where']=" WHERE emails.deleted=0 ";
2400 //$return_array['join'] = '';
2401 $return_array['join_tables'][0] = '';
2403 if(0 && $bean->object_name == "Case" && !empty($bean->case_number)) {
2404 $where = str_replace("%1", $bean->case_number, $bean->getEmailSubjectMacro());
2405 $return_array["where"] .= "\n AND emails.name LIKE '%$where%'";
2408 return $return_array;
2412 * Check to see if the number is empty or non-zero
2416 function number_empty($value)
2418 return empty($value) && $value != '0';
2421 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2424 require_once($beanFiles[$bean_name]);
2425 $focus = new $bean_name();
2426 $user_array = array();
2428 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2429 $user_array = get_register_value('select_array', $key );
2433 $db = DBManagerFactory::getInstance();
2435 $temp_result = Array();
2436 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2440 $query .= $where." AND ";
2443 $query .= " {$focus->table_name}.deleted=0";
2445 if ( $order_by != '')
2447 $query .= " order by {$focus->table_name}.{$order_by}";
2450 $GLOBALS['log']->debug("get_user_array query: $query");
2451 $result = $db->query($query, true, "Error filling in user array: ");
2453 if ($add_blank==true){
2454 // Add in a blank row
2455 if($blank_is_none == true) { // set 'blank row' to "--None--"
2456 global $app_strings;
2457 $temp_result[''] = $app_strings['LBL_NONE'];
2459 $temp_result[''] = '';
2463 // Get the id and the name.
2464 while($row = $db->fetchByAssoc($result))
2466 $temp_result[$row['id']] = $row['display'];
2469 $user_array = $temp_result;
2470 set_register_value('select_array', $key ,$temp_result);
2479 * @param unknown_type $listArray
2481 // function parse_list_modules
2482 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2483 function parse_list_modules(&$listArray)
2485 global $modListHeader;
2486 $returnArray = array();
2488 foreach($listArray as $optionName => $optionVal)
2490 if(array_key_exists($optionName, $modListHeader))
2492 $returnArray[$optionName] = $optionVal;
2495 // special case for projects
2496 if(array_key_exists('Project', $modListHeader))
2498 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2501 $acldenied = ACLController::disabledModuleList($listArray,false);
2502 foreach($acldenied as $denied){
2503 unset($returnArray[$denied]);
2505 asort($returnArray);
2507 return $returnArray;
2510 function display_notice($msg = false){
2511 global $error_notice;
2512 //no error notice - lets just display the error to the user
2513 if(!isset($error_notice)){
2514 echo '<br>'.$msg . '<br>';
2516 $error_notice .= $msg . '<br>';
2520 /* checks if it is a number that at least has the plus at the beginning.
2522 function skype_formatted($number){
2523 //kbrill - BUG #15375
2524 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2527 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2529 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2532 function format_skype($number) {
2533 return preg_replace('/[^\+0-9]/','',$number);
2536 function insert_charset_header() {
2537 header('Content-Type: text/html; charset=UTF-8');
2540 function getCurrentURL()
2543 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2548 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2552 function javascript_escape($str) {
2555 for($i = 0; $i < strlen($str); $i++) {
2557 if(ord(substr($str, $i, 1))==10){
2559 }elseif(ord(substr($str, $i, 1))==13){
2563 $new_str .= $str{$i};
2567 $new_str = str_replace("'", "\\'", $new_str);
2572 function js_escape($str, $keep=true){
2573 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2576 $str = javascript_escape($str);
2579 $str = str_replace("'", " ", $str);
2580 $str = str_replace('"', " ", $str);
2585 //end function js_escape
2588 function br2nl($str) {
2589 $regex = "#<[^>]+br.+?>#i";
2590 preg_match_all($regex, $str, $matches);
2592 foreach($matches[0] as $match) {
2593 $str = str_replace($match, "<br>", $str);
2596 $brs = array('<br>','<br/>', '<br />');
2597 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2598 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2599 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2600 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2606 * Private helper function for displaying the contents of a given variable.
2607 * This function is only intended to be used for SugarCRM internal development.
2608 * The ppd stands for Pre Print Die.
2610 function _ppd($mixed)
2616 * Private helper function for displaying the contents of a given variable in
2617 * the Logger. This function is only intended to be used for SugarCRM internal
2618 * development. The pp stands for Pre Print.
2619 * @param $mixed var to print_r()
2620 * @param $die boolean end script flow
2621 * @param $displayStackTrace also show stack trace
2623 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2624 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2626 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2630 $mix = print_r($mixed, true); // send print_r() output to $mix
2631 $stack = debug_backtrace();
2633 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2634 $GLOBALS['log']->$loglevel($mix);
2635 if($displayStackTrace) {
2636 foreach($stack as $position) {
2637 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2641 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2642 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2650 * private helper function to quickly show the major, direct, field attributes of a given bean.
2651 * The ppf stands for Pre[formatted] Print Focus [object]
2652 * @param object bean The focus bean
2654 function _ppf($bean, $die=false) {
2660 * Private helper function for displaying the contents of a given variable.
2661 * This function is only intended to be used for SugarCRM internal development.
2662 * The pp stands for Pre Print.
2664 function _pp($mixed)
2669 * Private helper function for displaying the contents of a given variable.
2670 * This function is only intended to be used for SugarCRM internal development.
2671 * The pp stands for Pre Print.
2673 function _pstack_trace($mixed=NULL)
2678 * Private helper function for displaying the contents of a given variable.
2679 * This function is only intended to be used for SugarCRM internal development.
2680 * The pp stands for Pre Print Trace.
2682 function _ppt($mixed, $textOnly=false)
2687 * Private helper function for displaying the contents of a given variable.
2688 * This function is only intended to be used for SugarCRM internal development.
2689 * The pp stands for Pre Print Trace Die.
2691 function _pptd($mixed)
2696 * Private helper function for decoding javascript UTF8
2697 * This function is only intended to be used for SugarCRM internal development.
2699 function decodeJavascriptUTF8($str) {
2703 * Will check if a given PHP version string is supported (tested on this ver),
2704 * unsupported (results unknown), or invalid (something will break on this
2705 * ver). Do not pass in any pararameter to default to a check against the
2706 * current environment's PHP version.
2708 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2710 function check_php_version($sys_php_version = '') {
2711 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2712 // versions below $min_considered_php_version considered invalid by default,
2713 // versions equal to or above this ver will be considered depending
2714 // on the rules that follow
2715 $min_considered_php_version = '5.2.1';
2717 // only the supported versions,
2718 // should be mutually exclusive with $invalid_php_versions
2719 $supported_php_versions = array (
2720 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2723 // invalid versions above the $min_considered_php_version,
2724 // should be mutually exclusive with $supported_php_versions
2726 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2727 $invalid_php_versions = array('5.2.7');
2729 // default unsupported
2732 // versions below $min_considered_php_version are invalid
2733 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2737 // supported version check overrides default unsupported
2738 foreach($supported_php_versions as $ver) {
2739 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2745 // invalid version check overrides default unsupported
2746 foreach($invalid_php_versions as $ver) {
2747 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2753 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2754 //and the php version contains 'rh' characters
2755 if(strpos($sys_php_version, 'rh') !== false) {
2763 * Will check if a given IIS version string is supported (tested on this ver),
2764 * unsupported (results unknown), or invalid (something will break on this
2767 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2769 function check_iis_version($sys_iis_version = '') {
2771 $server_software = $_SERVER["SERVER_SOFTWARE"];
2773 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2774 $iis_version = $out[1][0];
2776 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2778 // versions below $min_considered_iis_version considered invalid by default,
2779 // versions equal to or above this ver will be considered depending
2780 // on the rules that follow
2781 $min_considered_iis_version = '6.0';
2783 // only the supported versions,
2784 // should be mutually exclusive with $invalid_iis_versions
2785 $supported_iis_versions = array ('6.0', '7.0',);
2786 $unsupported_iis_versions = array();
2787 $invalid_iis_versions = array('5.0',);
2789 // default unsupported
2792 // versions below $min_considered_iis_version are invalid
2793 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2797 // supported version check overrides default unsupported
2798 foreach($supported_iis_versions as $ver) {
2799 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2805 // unsupported version check overrides default unsupported
2806 foreach($unsupported_iis_versions as $ver) {
2807 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2813 // invalid version check overrides default unsupported
2814 foreach($invalid_iis_versions as $ver) {
2815 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2824 function pre_login_check(){
2825 global $action, $login_error;
2826 if(!empty($action)&& $action == 'Login'){
2828 if(!empty($login_error)){
2829 $login_error = htmlentities($login_error);
2830 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2831 $_SESSION['login_error'] = $login_error;
2833 function set_focus() {}
2834 if(document.getElementById("post_error")) {
2835 document.getElementById("post_error").innerHTML="'. $login_error. '";
2836 document.getElementById("cant_login").value=1;
2837 document.getElementById("login_button").disabled = true;
2838 document.getElementById("user_name").disabled = true;
2839 //document.getElementById("user_password").disabled = true;
2848 function sugar_cleanup($exit = false) {
2849 static $called = false;
2852 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2853 chdir(realpath(dirname(__FILE__) . '/..'));
2854 global $sugar_config;
2855 require_once('include/utils/LogicHook.php');
2856 LogicHook::initialize();
2857 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2859 //added this check to avoid errors during install.
2860 if (empty($sugar_config['dbconfig'])) {
2861 if ($exit) exit; else return;
2864 if (!class_exists('Tracker', true)) {
2865 require_once 'modules/Trackers/Tracker.php';
2868 // Now write the cached tracker_queries
2869 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2870 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2871 $GLOBALS['current_user']->savePreferencesToDB();
2874 //check to see if this is not an `ajax call AND the user preference error flag is set
2876 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2877 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2878 && ($_REQUEST['action']!='favorites' && $_REQUEST['action']!='DynamicAction')
2879 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2880 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2883 global $app_strings;
2884 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2885 $err_mess = $app_strings['ERROR_USER_PREFS'];
2886 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2889 ajaxStatus.flashStatus('$err_mess',7000);
2895 if(class_exists('DBManagerFactory')) {
2896 $db = DBManagerFactory::getInstance();
2904 register_shutdown_function('sugar_cleanup');
2908 check_logic_hook - checks to see if your custom logic is in the logic file
2909 if not, it will add it. If the file isn't built yet, it will create the file
2912 function check_logic_hook_file($module_name, $event, $action_array){
2913 require_once('include/utils/logic_utils.php');
2916 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2918 $hook_array = get_hook_array($module_name);
2920 if(check_existing_element($hook_array, $event, $action_array)==true){
2921 //the hook at hand is present, so do nothing
2926 if(!empty($hook_array[$event]))
2928 $logic_count = count($hook_array[$event]);
2931 if($action_array[0]==""){
2932 $action_array[0] = $logic_count + 1;
2934 $hook_array[$event][] = $action_array;
2937 //end if the file exists already
2940 if($action_array[0]==""){
2941 $action_array[0] = 1;
2943 $hook_array = array();
2944 $hook_array[$event][] = $action_array;
2945 //end if else file exists already
2947 if($add_logic == true){
2949 //reorder array by element[0]
2950 //$hook_array = reorder_array($hook_array, $event);
2951 //!!!Finish this above TODO
2953 $new_contents = replace_or_add_logic_type($hook_array);
2954 write_logic_file($module_name, $new_contents);
2956 //end if add_element is true
2959 //end function check_logic_hook_file
2962 function remove_logic_hook($module_name, $event, $action_array) {
2963 require_once('include/utils/logic_utils.php');
2966 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2967 // The file exists, let's make sure the hook is there
2968 $hook_array = get_hook_array($module_name);
2970 if(check_existing_element($hook_array, $event, $action_array)==true){
2971 // The hook is there, time to take it out.
2973 foreach ( $hook_array[$event] as $i => $hook ) {
2974 // We don't do a full comparison below just in case the filename changes
2975 if ( $hook[0] == $action_array[0]
2976 && $hook[1] == $action_array[1]
2977 && $hook[3] == $action_array[3]
2978 && $hook[4] == $action_array[4] ) {
2979 unset($hook_array[$event][$i]);
2983 $new_contents = replace_or_add_logic_type($hook_array);
2984 write_logic_file($module_name, $new_contents);
2990 function display_stack_trace($textOnly=false){
2992 $stack = debug_backtrace();
2994 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
3002 foreach($stack as $item) {
3008 if(isset($item['file']))
3009 $file = $item['file'];
3010 if(isset($item['class']))
3011 $class = $item['class'];
3012 if(isset($item['line']))
3013 $line = $item['line'];
3014 if(isset($item['function']))
3015 $function = $item['function'];
3019 $out .= '<font color="black"><b>';
3025 $out .= '</b></font><font color="blue">';
3028 $out .= "[L:{$line}]";
3031 $out .= '</font><font color="red">';
3034 $out .= "({$class}:{$function})";
3037 $out .= '</font><br>';
3049 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
3050 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
3051 $halt_script = true;
3053 case 2048: return; //depricated we have lots of these ignore them
3056 if ( error_reporting() & E_NOTICE ) {
3057 $halt_script = false;
3063 case E_USER_WARNING:
3064 case E_COMPILE_WARNING:
3065 case E_CORE_WARNING:
3068 $halt_script = false;
3073 case E_COMPILE_ERROR:
3077 $type = "Fatal Error";
3082 $type = "Parse Error";
3086 //don't know what it is might not be so bad
3087 $halt_script = false;
3088 $type = "Unknown Error ($errno)";
3091 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3093 display_stack_trace();
3103 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3105 set_error_handler('StackTraceErrorHandler');
3107 function get_sub_cookies($name){
3109 if(isset($_COOKIE[$name])){
3110 $subs = explode('#', $_COOKIE[$name]);
3111 foreach($subs as $cookie){
3112 if(!empty($cookie)){
3113 $cookie = explode('=', $cookie);
3115 $cookies[$cookie[0]] = $cookie[1];
3124 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3126 if(!empty($sub_object_array)){
3128 foreach($sub_object_array as $sub_object){
3130 //run_second level is set to true if you need to remove sub-sub components
3131 if($run_second_level==true){
3133 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3135 //end if run_second_level is true
3137 $sub_object->mark_deleted($sub_object->id);
3138 //end foreach sub component
3140 //end if this is not empty
3143 //end function mark_delete_components
3147 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3149 function return_bytes($val)
3152 $last = strtolower($val{strlen($val)-1});
3156 // The 'G' modifier is available since PHP 5.1.0
3169 * Adds the href HTML tags around any URL in the $string
3171 function url2html($string) {
3173 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3174 return $return_string;
3176 // End customization by Julian
3179 * tries to determine whether the Host machine is a Windows machine
3181 function is_windows() {
3182 static $is_windows = null;
3183 if (!isset($is_windows)) {
3184 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3190 * equivalent for windows filesystem for PHP's is_writable()
3191 * @param string file Full path to the file/dir
3192 * @return bool true if writable
3194 function is_writable_windows($file) {
3195 if($file{strlen($file)-1}=='/') {
3196 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3199 // the assumption here is that Windows has an inherited permissions scheme
3200 // any file that is a descendant of an unwritable directory will inherit
3201 // that property and will trigger a failure below.
3206 $file = str_replace("/", '\\', $file);
3208 if(file_exists($file)) {
3209 if (!($f = @sugar_fopen($file, 'r+')))
3215 if(!($f = @sugar_fopen($file, 'w')))
3224 * best guesses Timezone based on webserver's TZ settings
3226 function lookupTimezone($userOffset = 0)
3228 return TimeDate::guessTimezone($userOffset);
3231 function convert_module_to_singular($module_array){
3234 foreach($module_array as $key => $value){
3235 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3237 if($value=="Cases") {
3238 $module_array[$key] = "Case";
3240 if($key=="projecttask"){
3241 $module_array['ProjectTask'] = "Project Task";
3242 unset($module_array[$key]);
3246 return $module_array;
3248 //end function convert_module_to_singular
3252 * Given the bean_name which may be plural or singular return the singular
3253 * bean_name. This is important when you need to include files.
3255 function get_singular_bean_name($bean_name){
3256 global $beanFiles, $beanList;
3257 if(array_key_exists($bean_name, $beanList)){
3258 return $beanList[$bean_name];
3266 * Given the potential module name (singular name, renamed module name)
3267 * Return the real internal module name.
3269 function get_module_from_singular($singular) {
3271 // find the internal module name for a singular name
3272 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3274 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3276 foreach ($singular_modules as $mod_name=>$sin_name) {
3277 if ($singular == $sin_name and $mod_name != $sin_name) {
3283 // find the internal module name for a renamed module
3284 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3286 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3288 foreach ($moduleList as $mod_name=>$name) {
3289 if ($singular == $name and $mod_name != $name) {
3295 // if it's not a singular name, nor a renamed name, return the original value
3299 function get_label($label_tag, $temp_module_strings){
3300 global $app_strings;
3301 if(!empty($temp_module_strings[$label_tag])){
3303 $label_name = $temp_module_strings[$label_tag];
3305 if(!empty($app_strings[$label_tag])){
3306 $label_name = $app_strings[$label_tag];
3308 $label_name = $label_tag;
3313 //end function get_label
3317 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3319 $rel_list = array();
3321 foreach($focus->relationship_fields as $rel_key => $rel_value){
3322 if($rel_value == $relationship_name){
3323 $temp_bean = get_module_info($tar_rel_module);
3324 // echo $focus->$rel_key;
3325 $temp_bean->retrieve($focus->$rel_key);
3326 if($temp_bean->id!=""){
3328 $rel_list[] = $temp_bean;
3334 foreach($focus->field_defs as $field_name => $field_def){
3335 //Check if the relationship_name matches a "relate" field
3336 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3337 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3338 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3339 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3341 $temp_bean = get_module_info($tar_rel_module);
3342 // echo $focus->$field_def['id_name'];
3343 $temp_bean->retrieve($focus->$field_def['id_name']);
3344 if($temp_bean->id!=""){
3346 $rel_list[] = $temp_bean;
3349 //Check if the relationship_name matches a "link" in a relate field
3350 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3351 $temp_bean = get_module_info($tar_rel_module);
3352 // echo $focus->$rel_value['id_name'];
3353 $temp_bean->retrieve($focus->$rel_value['id_name']);
3354 if($temp_bean->id!=""){
3356 $rel_list[] = $temp_bean;
3362 // special case for unlisted parent-type relationships
3363 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3364 $temp_bean = get_module_info($tar_rel_module);
3365 $temp_bean->retrieve($focus->parent_id);
3366 if($temp_bean->id!=""){
3367 $rel_list[] = $temp_bean;
3374 //end function search_filter_rel_info
3377 function get_module_info($module_name){
3381 //Get dictionary and focus data for module
3382 $vardef_name = $beanList[$module_name];
3384 if($vardef_name=="aCase"){
3385 $class_name = "Case";
3387 $class_name = $vardef_name;
3390 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3394 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3396 $module_bean = new $vardef_name();
3397 return $module_bean;
3398 //end function get_module_table
3402 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3404 * @param string $moduleName
3406 function get_valid_bean_name($module_name){
3409 $vardef_name = $beanList[$module_name];
3410 if($vardef_name=="aCase"){
3411 $bean_name = "Case";
3413 $bean_name = $vardef_name;
3420 function checkAuthUserStatus(){
3427 * This function returns an array of phpinfo() results that can be parsed and
3428 * used to figure out what version we run, what modules are compiled in, etc.
3429 * @param $level int info level constant (1,2,4,8...64);
3430 * @return $returnInfo array array of info about the PHP environment
3431 * @author original by "code at adspeed dot com" Fron php.net
3432 * @author customized for Sugar by Chris N.
3434 function getPhpInfo($level=-1) {
3435 /** Name (constant) Value Description
3436 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3437 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3438 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3439 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3440 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3441 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3442 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3443 INFO_ALL -1 Shows all of the above. This is the default value.
3447 $phpinfo = ob_get_contents();
3450 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3451 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3452 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3453 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3456 $returnInfo = array();
3458 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3459 $returnInfo['PHP Version'] = $version[1];
3463 for ($i=1; $i<count($parsedInfo); $i++) {
3464 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3465 $vName = trim($match[1]);
3466 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3468 foreach ($parsedInfo2 AS $vOne) {
3469 $vPat = '<info>([^<]+)<\/info>';
3470 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3471 $vPat2 = "/$vPat\s*$vPat/";
3473 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3474 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3475 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3476 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3488 * This function will take a string that has tokens like {0}, {1} and will replace
3489 * those tokens with the args provided
3490 * @param $format string to format
3491 * @param $args args to replace
3492 * @return $result a formatted string
3494 function string_format($format, $args){
3498 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3499 * IN () fails and IN ('') works.
3501 if (count($args) == 1)
3504 $singleArgument = current($args);
3505 if (empty($singleArgument))
3507 return str_replace("{0}", "''", $result);
3512 for($i = 0; $i < count($args); $i++){
3513 $result = str_replace('{'.$i.'}', $args[$i], $result);
3519 * Generate a string for displaying a unique identifier that is composed
3520 * of a system_id and number. This is use to allow us to generate quote
3521 * numbers using a DB auto-increment key from offline clients and still
3522 * have the number be unique (since it is modified by the system_id.
3524 * @param $num of bean
3525 * @param $system_id from system
3526 * @return $result a formatted string
3528 function format_number_display($num, $system_id){
3529 global $sugar_config;
3530 if(isset($num) && !empty($num)){
3531 $num=unformat_number($num);
3532 if(isset($system_id) && $system_id == 1){
3533 return sprintf("%d", $num);
3536 return sprintf("%d-%d", $num, $system_id);
3540 function checkLoginUserStatus(){
3544 * This function will take a number and system_id and format
3545 * @param $url URL containing host to append port
3546 * @param $port the port number - if '' is passed, no change to url
3547 * @return $resulturl the new URL with the port appended to the host
3549 function appendPortToHost($url, $port)
3553 // if no port, don't change the url
3556 $split = explode("/", $url);
3557 //check if it starts with http, in case they didn't include that in url
3558 if(str_begin($url, 'http'))
3560 //third index ($split[2]) will be the host
3561 $split[2] .= ":".$port;
3563 else // otherwise assumed to start with host name
3565 //first index ($split[0]) will be the host
3566 $split[0] .= ":".$port;
3569 $resulturl = implode("/", $split);
3576 * Singleton to return JSON object
3577 * @return JSON object
3579 function getJSONobj() {
3580 static $json = null;
3582 require_once('include/JSON.php');
3583 $json = new JSON(JSON_LOOSE_TYPE);
3588 require_once('include/utils/db_utils.php');
3591 * Set default php.ini settings for entry points
3593 function setPhpIniSettings() {
3595 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3597 if(function_exists('gzclose') && headers_sent() == false) {
3598 ini_set('zlib.output_compression', 1);
3602 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3604 /*if(function_exists('mb_strlen')) {
3605 ini_set('mbstring.func_overload', 7);
3606 ini_set('mbstring.internal_encoding', 'UTF-8');
3610 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3611 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3612 $backtrack_limit = ini_get('pcre.backtrack_limit');
3613 if(!empty($backtrack_limit)) {
3614 ini_set('pcre.backtrack_limit', '-1');
3619 * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
3620 * language files. Language file merges do not need to account for null values so we can get some
3621 * performance increases by using this specialized function. Note this merge function does not properly
3622 * handle null values.
3628 function sugarLangArrayMerge($gimp, $dom)
3630 if(is_array($gimp) && is_array($dom))
3632 foreach($dom as $domKey => $domVal)
3634 if(isset($gimp[$domKey]))
3636 if(is_array($domVal))
3639 foreach ( $domVal as $domArrKey => $domArrVal )
3640 $tempArr[$domArrKey] = $domArrVal;
3641 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3642 if ( !isset($tempArr[$gimpArrKey]) )
3643 $tempArr[$gimpArrKey] = $gimpArrVal;
3644 $gimp[$domKey] = $tempArr;
3648 $gimp[$domKey] = $domVal;
3653 $gimp[$domKey] = $domVal;
3657 // if the passed value for gimp isn't an array, then return the $dom
3658 elseif(is_array($dom))
3666 * like array_merge() but will handle array elements that are themselves arrays;
3667 * PHP's version just overwrites the element with the new one.
3669 * @internal Note that this function deviates from the internal array_merge()
3670 * functions in that it does does not treat numeric keys differently
3671 * than string keys. Additionally, it deviates from
3672 * array_merge_recursive() by not creating an array when like values
3675 * @param array gimp the array whose values will be overloaded
3676 * @param array dom the array whose values will pwn the gimp's
3677 * @return array beaten gimp
3679 function sugarArrayMerge($gimp, $dom) {
3680 if(is_array($gimp) && is_array($dom)) {
3681 foreach($dom as $domKey => $domVal) {
3682 if(array_key_exists($domKey, $gimp)) {
3683 if(is_array($domVal)) {
3685 foreach ( $domVal as $domArrKey => $domArrVal )
3686 $tempArr[$domArrKey] = $domArrVal;
3687 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3688 if ( !array_key_exists($gimpArrKey, $tempArr) )
3689 $tempArr[$gimpArrKey] = $gimpArrVal;
3690 $gimp[$domKey] = $tempArr;
3692 $gimp[$domKey] = $domVal;
3695 $gimp[$domKey] = $domVal;
3699 // if the passed value for gimp isn't an array, then return the $dom
3700 elseif(is_array($dom))
3707 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3709 * @param array gimp the array whose values will be overloaded
3710 * @param array dom the array whose values will pwn the gimp's
3711 * @return array beaten gimp
3713 function sugarArrayMergeRecursive($gimp, $dom) {
3714 if(is_array($gimp) && is_array($dom)) {
3715 foreach($dom as $domKey => $domVal) {
3716 if(array_key_exists($domKey, $gimp)) {
3717 if(is_array($domVal) && is_array($gimp[$domKey])) {
3718 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3720 $gimp[$domKey] = $domVal;
3723 $gimp[$domKey] = $domVal;
3727 // if the passed value for gimp isn't an array, then return the $dom
3728 elseif(is_array($dom))
3735 * finds the correctly working versions of PHP-JSON
3736 * @return bool True if NOT found or WRONG version
3738 function returnPhpJsonStatus() {
3739 if(function_exists('json_encode')) {
3740 $phpInfo = getPhpInfo(8);
3741 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3743 return true; // not found
3748 * getTrackerSubstring
3750 * Returns a [number]-char or less string for the Tracker to display in the header
3751 * based on the tracker_max_display_length setting in config.php. If not set,
3752 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3754 * @param string name field for a given Object
3755 * @return string [number]-char formatted string if length of string exceeds the max allowed
3757 function getTrackerSubstring($name) {
3758 static $max_tracker_item_length;
3761 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3762 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3764 global $sugar_config;
3766 if(!isset($max_tracker_item_length)) {
3767 if(isset($sugar_config['tracker_max_display_length'])) {
3768 $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;
3770 $max_tracker_item_length = 15;
3774 if($strlen > $max_tracker_item_length) {
3775 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length);
3782 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3783 $where_clauses= array();
3785 $table_name=$bean->object_name;
3786 foreach ($field_list[$module] as $field=>$parms) {
3787 if(isset($values[$field]) && $values[$field] != "") {
3789 if (!empty($parms['operator'])) {
3790 $operator=$parms['operator'];
3792 if (is_array($values[$field])) {
3795 foreach ($values[$field] as $key => $val) {
3796 if ($val != ' ' and $val != '') {
3797 if (!empty($field_value)) {
3800 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3804 $field_value=$GLOBALS['db']->quote($values[$field]);
3806 //set db_fields array.
3807 if (!isset($parms['db_field']) ) {
3808 $parms['db_field'] = array($field);
3810 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3811 global $current_user;
3812 $field_value = $GLOBALS['db']->quote($current_user->id);
3818 if ($field_value != '') {
3820 foreach ($parms['db_field'] as $db_field) {
3821 if (strstr($db_field,'.')===false) {
3822 $db_field=$bean->table_name.".".$db_field;
3824 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3825 $db_field='upper('.$db_field.")";
3826 $field_value=strtoupper($field_value);
3830 if (!empty($where)) {
3833 switch (strtolower($operator)) {
3835 $where .= $db_field . " like '".$field_value.$like_char."'";
3838 $where .= $db_field . " in (".$field_value.')';
3841 $where .= $db_field . " = '".$field_value ."'";
3846 if (!empty($where)) {
3848 array_push($where_clauses, '( '.$where.' )');
3850 array_push($where_clauses, $where);
3855 if ($add_custom_fields) {
3856 require_once('modules/DynamicFields/DynamicField.php');
3857 $bean->setupCustomFields($module);
3858 $bean->custom_fields->setWhereClauses($where_clauses);
3860 return $where_clauses;
3863 function add_quotes($str) {
3868 * This function will rebuild the config file
3869 * @param $sugar_config
3870 * @param $sugar_version
3871 * @return bool true if successful
3873 function rebuildConfigFile($sugar_config, $sugar_version) {
3874 // add defaults to missing values of in-memory sugar_config
3875 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3876 // need to override version with default no matter what
3877 $sugar_config['sugar_version'] = $sugar_version;
3879 ksort( $sugar_config );
3881 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3890 * getJavascriptSiteURL
3891 * This function returns a URL for the client javascript calls to access
3892 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3893 * are used to access the site. Thus, the hostname in the URL returned may
3894 * not always match that of $sugar_config['site_url']. Basically, the
3895 * assumption is that however the user accessed the website is how they
3896 * will continue to with subsequent javascript requests. If the variable
3897 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3898 * @return $site_url The url used to refer to the website
3900 function getJavascriptSiteURL() {
3901 global $sugar_config;
3902 if(!empty($_SERVER['HTTP_REFERER'])) {
3903 $url = parse_url($_SERVER['HTTP_REFERER']);
3904 $replacement_url = $url['scheme']."://".$url['host'];
3905 if(!empty($url['port']))
3906 $replacement_url .= ':'.$url['port'];
3907 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3909 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3910 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3911 $site_url = preg_replace('/^http\:/','https:',$site_url);
3914 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3918 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3919 function add_squotes($str) {
3920 return "'" . $str . "'";
3924 // recursive function to count the number of levels within an array
3925 function array_depth($array, $depth_count=-1, $depth_array=array()){
3927 if (is_array($array)){
3928 foreach ($array as $key => $value){
3929 $depth_array[] = array_depth($value, $depth_count);
3933 return $depth_count;
3935 foreach ($depth_array as $value){
3936 $depth_count = $value > $depth_count ? $value : $depth_count;
3938 return $depth_count;
3942 * Creates a new Group User
3943 * @param string $name Name of Group User
3944 * @return string GUID of new Group User
3946 function createGroupUser($name) {
3949 $group = new User();
3950 $group->user_name = $name;
3951 $group->last_name = $name;
3952 $group->is_group = 1;
3953 $group->deleted = 0;
3954 $group->status = 'Active'; // cn: bug 6711
3955 $group->setPreference('timezone', TimeDate::userTimezone());
3962 * Helper function to locate an icon file given only a name
3963 * Searches through the various paths for the file
3964 * @param string iconFileName The filename of the icon
3965 * @return string Relative pathname of the located icon, or '' if not found
3968 function _getIcon($iconFileName)
3971 $iconName = "icon_{$iconFileName}.gif";
3972 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3974 //First try un-ucfirst-ing the icon name
3975 if ( empty($iconFound) )
3976 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3977 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3979 //Next try removing the icon prefix
3980 if ( empty($iconFound) )
3981 $iconName = "{$iconFileName}.gif";
3982 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3984 if ( empty($iconFound) )
3990 * Function to grab the correct icon image for Studio
3991 * @param string $iconFileName Name of the icon file
3992 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3993 * @param string $width Width of image
3994 * @param string $height Height of image
3995 * @param string $align Alignment of image
3996 * @param string $alt Alt tag of image
3997 * @return string $string <img> tag with corresponding image
4000 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
4002 global $app_strings, $theme;
4004 $iconName = _getIcon($iconFileName);
4005 if(empty($iconName)){
4006 $iconName = _getIcon($altFileName);
4007 if (empty($iconName))
4009 return $app_strings['LBL_NO_IMAGE'];
4012 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4016 * Function to grab the correct icon image for Dashlets Dialog
4017 * @param string $filename Location of the icon file
4018 * @param string $module Name of the module to fall back onto if file does not exist
4019 * @param string $width Width of image
4020 * @param string $height Height of image
4021 * @param string $align Alignment of image
4022 * @param string $alt Alt tag of image
4023 * @return string $string <img> tag with corresponding image
4026 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
4027 global $app_strings, $theme;
4028 $iconName = _getIcon($module . "_32");
4029 if (empty($iconName))
4031 $iconName = _getIcon($module);
4033 if(empty($iconName)){
4034 return $app_strings['LBL_NO_IMAGE'];
4036 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4039 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
4040 function html_entity_decode_utf8($string)
4043 // replace numeric entities
4044 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
4045 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
4046 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
4047 // replace literal entities
4048 if (!isset($trans_tbl))
4050 $trans_tbl = array();
4051 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
4052 $trans_tbl[$key] = utf8_encode($val);
4054 return strtr($string, $trans_tbl);
4057 // Returns the utf string corresponding to the unicode value
4058 function code2utf($num)
4060 if ($num < 128) return chr($num);
4061 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
4062 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4063 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4067 function str_split_php4($string, $length = 1) {
4068 $string_length = strlen($string);
4071 if ($length > $string_length) {
4072 // use the string_length as the string is shorter than the length
4073 $length = $string_length;
4075 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
4076 $return[] = substr($string, $cursor, $length);
4081 if (version_compare(phpversion(), '5.0.0', '<')) {
4082 function str_split($string, $length = 1) {
4083 return str_split_php4($string, $length);
4088 * @deprecated use DBManagerFactory::isFreeTDS
4090 function is_freetds()
4092 return DBManagerFactory::isFreeTDS();
4096 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
4098 * @todo this won't work completely right until we impliment css compression and combination
4099 * for now, we'll just include the last css file found.
4101 * @return chart.css file to use
4103 function chartStyle()
4105 return SugarThemeRegistry::current()->getCSSURL('chart.css');
4109 * Chart dashlet helper functions that returns the correct XML color file for charts,
4110 * dependent on the current theme.
4112 * @return sugarColors.xml to use
4114 function chartColors()
4116 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
4117 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4118 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4120 /* End Chart Dashlet helper functions */
4123 * This function is designed to set up the php enviroment
4124 * for AJAX requests.
4127 function ajaxInit() {
4128 ini_set('display_errors', 'false');
4132 * Returns an absolute path from the given path, determining if it is relative or absolute
4134 * @param string $path
4137 function getAbsolutePath(
4139 $currentServer = false
4142 $path = trim($path);
4144 // try to match absolute paths like \\server\share, /directory or c:\
4145 if ( ( substr($path,0,2) == '\\\\' )
4146 || ( $path[0] == '/' )
4147 || preg_match('/^[A-z]:/i',$path)
4151 return getcwd().'/'.$path;
4155 * Returns the bean object of the given module
4157 * @deprecated use SugarModule::loadBean() instead
4158 * @param string $module
4165 return SugarModule::get($module)->loadBean();
4170 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4172 function isTouchScreen()
4174 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4176 // first check if we have forced use of the touch enhanced interface
4177 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4181 // next check if we should use the touch interface with our device
4182 if ( strpos($ua, 'ipad') !== false ) {
4190 * Returns the shortcut keys to access the shortcut links. Shortcut
4191 * keys vary depending on browser versions and operating systems.
4192 * @return String value of the shortcut keys
4194 function get_alt_hot_key() {
4196 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4197 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4198 $isMac = strpos($ua, 'mac') !== false;
4199 $isLinux = strpos($ua, 'linux') !== false;
4201 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4202 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4203 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4206 return $isMac ? 'Ctrl+' : 'Alt+';
4209 function can_start_session(){
4210 if(!empty($_GET['PHPSESSID'])) {
4213 $session_id = session_id();
4214 return empty($session_id) ? true : false;
4217 function load_link_class($properties){
4219 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4220 require_once($properties['link_file']);
4221 $class = $properties['link_class'];
4227 function inDeveloperMode()
4229 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4233 * Filter the protocol list for inbound email accounts.
4235 * @param array $protocol
4237 function filterInboundEmailPopSelection($protocol)
4239 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4241 if( isset($protocol['pop3']) )
4242 unset($protocol['pop3']);
4245 $protocol['pop3'] = 'POP3';
4251 * The function is used because currently we are not supporting mbstring.func_overload
4252 * 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.
4253 * 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.
4254 * @returns the substred strings.
4256 function sugar_substr($string, $length, $charset='UTF-8')
4258 if(mb_strlen($string,$charset) > $length) {
4259 $string = trim(mb_substr(trim($string),0,$length,$charset));
4265 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4266 * This will work even without setting the mbstring.*encoding
4268 function sugar_ucfirst($string, $charset='UTF-8') {
4269 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4276 function unencodeMultienum($string) {
4277 if (is_array($string))
4281 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4282 $string = substr(substr($string, 1), 0, strlen($string) -2);
4285 return explode('^,^', $string);
4288 function encodeMultienumValue($arr) {
4289 if (!is_array($arr))
4295 $string = "^" . implode('^,^', $arr) . "^";
4301 * create_export_query is used for export and massupdate
4302 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4303 * This function will correct the where clause and output necessary join condition for them
4304 * @param $module: the module name
4305 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4306 * @param $where: where clauses
4307 * @return $ret_array['where']: corrected where clause
4308 * @return $ret_array['join']: extra join condition
4310 function create_export_query_relate_link_patch($module, $searchFields, $where){
4311 if(file_exists('modules/'.$module.'/SearchForm.html')){
4312 $ret_array['where'] = $where;
4315 $seed = loadBean($module);
4316 foreach($seed->field_defs as $name=>$field)
4319 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4320 $seed->load_relationship($field['link']);
4322 if(empty($join_type))
4324 $params['join_type'] = ' LEFT JOIN ';
4328 $params['join_type'] = $join_type;
4330 if(isset($data['join_name']))
4332 $params['join_table_alias'] = $field['join_name'];
4336 $params['join_table_alias'] = 'join_'.$field['name'];
4339 if(isset($data['join_link_name']))
4341 $params['join_table_link_alias'] = $field['join_link_name'];
4345 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4347 $join = $seed->$field['link']->getJoin($params, true);
4348 $join_table_alias = 'join_'.$field['name'];
4349 if(isset($field['db_concat_fields'])){
4350 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4351 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4353 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4357 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4362 * 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.
4363 * @Depends on QuickRepairAndRebuild.php
4364 * @Relate bug 30642 ,23177
4366 function clearAllJsAndJsLangFilesWithoutOutput(){
4367 global $current_language , $mod_strings;
4368 $MBmodStrings = $mod_strings;
4369 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4370 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4371 $repair = new RepairAndClear();
4372 $repair->module_list = array();
4373 $repair->show_output = false;
4374 $repair->clearJsLangFiles();
4375 $repair->clearJsFiles();
4376 $mod_strings = $MBmodStrings;
4380 * This function will allow you to get a variable value from query string
4382 function getVariableFromQueryString($variable, $string){
4384 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4394 * should_hide_iframes
4395 * This is a helper method to determine whether or not to show iframes (My Sites) related
4396 * information in the application.
4398 * @return boolean flag indicating whether or not iframes module should be hidden
4400 function should_hide_iframes() {
4401 //Remove the MySites module
4402 if(file_exists('modules/iFrames/iFrame.php')) {
4403 if(!class_exists("iFrame")) {
4404 require_once('modules/iFrames/iFrame.php');
4412 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4414 * @param string $version
4415 * @return string RC, BETA, GA
4417 function getVersionStatus($version){
4418 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4419 return strtoupper($matches[1]);
4426 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4427 * 5.5.1RC1 then return 5.5.1
4429 * @param string $version
4432 function getMajorMinorVersion($version){
4433 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4434 $version = $matches2[1];
4435 $arr = explode('.', $version);
4436 if(count($arr) > 2){
4438 $version = substr($version, 0, 3);
4446 * Return string composed of seconds & microseconds of current time, without dots
4449 function sugar_microtime()
4451 $now = explode(' ', microtime());
4452 $unique_id = $now[1].str_replace('.', '', $now[0]);
4457 * Extract urls from a piece of text
4459 * @return array of urls found in $string
4461 function getUrls($string)
4463 $lines = explode("<br>", trim($string));
4465 foreach($lines as $line){
4466 $regex = '/http?\:\/\/[^\" ]+/i';
4467 preg_match_all($regex, $line, $matches);
4468 foreach($matches[0] as $match){
4477 * Sanitize image file from hostile content
4478 * @param string $path Image file
4479 * @param bool $jpeg Accept only JPEGs?
4481 function verify_image_file($path, $jpeg = false)
4483 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4484 $img = imagecreatefromstring(file_get_contents($path));
4488 $img_size = getimagesize($path);
4489 $filetype = $img_size['mime'];
4490 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4491 if($filetype == "image/jpeg" || $jpeg) {
4494 $image = ob_get_clean();
4495 // not writing directly because imagejpeg does not work with streams
4496 if(file_put_contents($path, $image)) {
4499 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4500 imagealphablending($img, true);
4501 imagesavealpha($img, true);
4504 $image = ob_get_clean();
4505 if(file_put_contents($path, $image)) {
4512 // check image manually
4513 $fp = fopen($path, "r");
4514 if(!$fp) return false;
4515 $data = fread($fp, 4096);
4517 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",
4519 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4528 * Verify uploaded image
4529 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4530 * @param string $path Image path
4531 * @param bool $jpeg_only Accept only JPEGs?
4533 function verify_uploaded_image($path, $jpeg_only = false)
4535 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4537 $supportedExtensions['png'] = 'image/png';
4540 if(!file_exists($path) || !is_file($path)) {
4544 $img_size = getimagesize($path);
4545 $filetype = $img_size['mime'];
4546 $ext = end(explode(".", $path));
4547 if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4548 !in_array($filetype, array_values($supportedExtensions))) {
4551 return verify_image_file($path, $jpeg_only);
4554 function cmp_beans($a, $b)
4556 global $sugar_web_service_order_by;
4557 //If the order_by field is not valid, return 0;
4558 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4561 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4562 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4566 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4574 function order_beans($beans, $field_name)
4576 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4577 global $sugar_web_service_order_by;
4578 $sugar_web_service_order_by = $field_name;
4579 usort($beans, "cmp_beans");
4584 * Return search like string
4585 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4586 * @param string $str string to be searched
4587 * @param string $like_char Database like character, usually '%'
4588 * @return string Returns a string to be searched in db query
4590 function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true) {
4592 // override default wildcard character
4593 if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4594 strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4595 $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4598 // add wildcard at the beginning of the search string
4599 if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4600 $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4601 if (substr($str,0,1) <> $wildcard)
4602 $str = $wildcard.$str;
4605 // add wildcard at the end of search string (default)
4606 if ($appendWildcard) {
4607 if(substr($str,-1) <> $wildcard) {
4612 return str_replace($wildcard, $like_char, $str);
4615 //check to see if custom utils exists
4616 if(file_exists('custom/include/custom_utils.php')){
4617 include_once('custom/include/custom_utils.php');
4620 //check to see if custom utils exists in Extension framework
4621 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4622 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4625 * @param $input - the input string to sanitize
4626 * @param int $quotes - use quotes
4627 * @param string $charset - the default charset
4628 * @param bool $remove - strip tags or not
4629 * @return string - the sanitized string
4631 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4633 return htmlentities($input, $quotes, $charset);
4637 * @return string - the full text search engine name
4639 function getFTSEngineType()
4641 if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
4642 foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
4650 * @param string $optionName - name of the option to be retrieved from app_list_strings
4651 * @return array - the array to be used in option element
4653 function getFTSBoostOptions($optionName)
4655 if (isset($GLOBALS['app_list_strings'][$optionName])) {
4656 return $GLOBALS['app_list_strings'][$optionName];
4664 * utf8_recursive_encode
4666 * This function walks through an Array and recursively calls utf8_encode on the
4667 * values of each of the elements.
4669 * @param $data Array of data to encode
4670 * @return utf8 encoded Array data
4672 function utf8_recursive_encode($data)
4675 foreach($data as $key=>$val) {
4676 if(is_array($val)) {
4677 $result[$key] = utf8_recursive_encode($val);
4679 $result[$key] = utf8_encode($val);
4686 * get_language_header
4688 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4689 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4691 * @return String The lang=[Current Language] markup to insert into the <html> tag
4693 function get_language_header()
4695 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4700 * get_custom_file_if_exists
4702 * This function handles the repetitive code we have where we first check if a file exists in the
4703 * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
4704 * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
4705 * otherwise it return $file
4707 * @param $file String of filename to check
4708 * @return $file String of filename including custom directory if found
4710 function get_custom_file_if_exists($file)
4712 return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4719 * This will return the URL used to redirect the user to the help documentation.
4720 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4721 * in config.php or config_override.php.
4723 * @param string $send_edition
4724 * @param string $send_version
4725 * @param string $send_lang
4726 * @param string $send_module
4727 * @param string $send_action
4728 * @param string $dev_status
4729 * @param string $send_key
4730 * @param string $send_anchor
4731 * @return string the completed help URL
4733 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4734 global $sugar_config;
4736 if (!empty($sugar_config['custom_help_url'])) {
4737 $sendUrl = $sugar_config['custom_help_url'];
4739 if (!empty($sugar_config['custom_help_base_url'])) {
4740 $baseUrl= $sugar_config['custom_help_base_url'];
4742 $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4744 $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4745 if(!empty($send_anchor)) {
4746 $sendUrl .= "&anchor=".$send_anchor;
4753 * generateETagHeader
4755 * This function generates the necessary cache headers for using ETags with dynamic content. You
4756 * simply have to generate the ETag, pass it in, and the function handles the rest.
4758 * @param string $etag ETag to use for this content.
4760 function generateETagHeader($etag){
4761 header("cache-control:");
4762 header('Expires: ');
4763 header("ETag: " . $etag);
4765 if(isset($_SERVER["HTTP_IF_NONE_MATCH"])){
4766 if($etag == $_SERVER["HTTP_IF_NONE_MATCH"]){
4768 header("Status: 304 Not Modified");
4769 header("HTTP/1.0 304 Not Modified");