2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
37 /*********************************************************************************
39 * Description: Includes generic helper functions used throughout the application.
40 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41 * All Rights Reserved.
42 * Contributor(s): ______________________________________..
43 ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/security_utils.php');
49 function make_sugar_config(&$sugar_config)
51 /* used to convert non-array config.php file to array format */
52 global $admin_export_only;
54 global $calculate_response_time;
55 global $create_default_user;
58 global $dbconfigoption;
59 global $default_action;
60 global $default_charset;
61 global $default_currency_name;
62 global $default_currency_symbol;
63 global $default_currency_iso4217;
64 global $defaultDateFormat;
65 global $default_language;
66 global $default_module;
67 global $default_password;
68 global $default_permission_mode;
69 global $default_theme;
70 global $defaultTimeFormat;
71 global $default_user_is_admin;
72 global $default_user_name;
73 global $disable_export;
74 global $disable_persistent_connections;
75 global $display_email_template_variable_chooser;
76 global $display_inbound_email_buttons;
77 global $history_max_viewed;
81 global $list_max_entries_per_page;
82 global $lock_default_user_name;
83 global $log_memory_usage;
85 global $requireAccounts;
86 global $RSS_CACHE_TIME;
90 global $sugar_version;
93 global $translation_string_prefix;
95 global $upload_badext;
97 global $upload_maxsize;
98 global $import_max_execution_time;
99 global $list_max_entries_per_subpanel;
100 global $passwordsetting;
102 // assumes the following variables must be set:
103 // $dbconfig, $dbconfigoption, $cache_dir, $session_dir, $site_URL, $upload_dir
105 $sugar_config = array (
106 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
107 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
108 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
109 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
110 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
111 'chartEngine' => 'Jit',
112 'date_formats' => empty($dateFormats) ? array(
113 'Y-m-d'=>'2010-12-23',
114 'd-m-Y' => '23-12-2010',
115 'm-d-Y'=>'12-23-2010',
116 'Y/m/d'=>'2010/12/23',
117 'd/m/Y' => '23/12/2010',
118 'm/d/Y'=>'12/23/2010',
119 'Y.m.d' => '2010.12.23',
120 'd.m.Y' => '23.12.2010',
121 'm.d.Y' => '12.23.2010'
123 'dbconfig' => $dbconfig, // this must be set!!
124 'dbconfigoption' => $dbconfigoption, // this must be set!!
125 'default_action' => empty($default_action) ? 'index' : $default_action,
126 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
127 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
128 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
129 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
130 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
131 'default_locale_name_format' => empty($defaultNameFormat) ? 's f l' : $defaultNameFormat,
132 'default_export_charset' => 'UTF-8',
133 'default_language' => empty($default_language) ? 'en_us' : $default_language,
134 'default_module' => empty($default_module) ? 'Home' : $default_module,
135 'default_password' => empty($default_password) ? '' : $default_password,
136 'default_permissions' => array (
142 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
143 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
144 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
145 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
146 'disable_export' => empty($disable_export) ? false : $disable_export,
147 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
148 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
149 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
150 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
151 'host_name' => empty($host_name) ? 'localhost' : $host_name,
152 'import_dir' => $import_dir, // this must be set!!
153 'import_max_records_per_file' => 100,
154 'import_max_records_total_limit' => '',
155 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
156 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
157 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
158 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
159 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
160 'name_formats' => empty($nameFormats) ? array(
161 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
162 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
164 'portal_view' => 'single_user',
165 'resource_management' => array (
166 'special_query_limit' => 50000,
167 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
168 'default_limit' => 1000,
170 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
171 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
172 'session_dir' => $session_dir, // this must be set!!
173 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
174 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
175 'showThemePicker' => true,
176 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
177 'time_formats' => empty($timeFormats) ? array (
178 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
179 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
180 'tmp_dir' => $tmp_dir, // this must be set!!
181 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
182 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
183 'upload_badext' => empty($upload_badext) ? array (
184 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
185 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
186 'upload_dir' => $upload_dir, // this must be set!!
187 'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
188 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
189 'lock_homepage' => false,
190 'lock_subpanels' => false,
191 'max_dashlets_homepage' => 15,
192 'dashlet_display_row_options' => array('1','3','5','10'),
193 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
194 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
195 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
196 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
197 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
198 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
199 'default_call_status' => 'Planned',
200 'js_lang_version' => 1,
201 'passwordsetting' => empty($passwordsetting) ? array (
202 'SystemGeneratedPasswordON' => '',
203 'generatepasswordtmpl' => '',
204 'lostpasswordtmpl' => '',
205 'forgotpasswordON' => true,
206 'linkexpiration' => '1',
207 'linkexpirationtime' => '30',
208 'linkexpirationtype' => '1',
209 'systexpiration' => '0',
210 'systexpirationtime' => '',
211 'systexpirationtype' => '0',
212 'systexpirationlogin' => '',
213 ) : $passwordsetting,
214 'use_sprites' => function_exists('imagecreatetruecolor'),
215 'search_wildcard_infront' => false,
216 'search_wildcard_char' => '%',
220 function get_sugar_config_defaults() {
223 * used for getting base values for array style config.php. used by the
224 * installer and to fill in new entries on upgrades. see also:
228 $sugar_config_defaults = array (
229 'admin_export_only' => false,
230 'export_delimiter' => ',',
231 'cache_dir' => 'cache/',
232 'calculate_response_time' => true,
233 'create_default_user' => false,
234 'chartEngine' => 'Jit',
235 'date_formats' => array (
236 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
237 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
238 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
239 'name_formats' => array (
240 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
241 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
243 'dbconfigoption' => array (
244 'persistent' => true,
248 'default_action' => 'index',
249 'default_charset' => return_session_value_or_default('default_charset',
251 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
252 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
253 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
254 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
255 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
256 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
257 'default_date_format' => 'm/d/Y',
258 'default_locale_name_format' => 's f l',
259 'default_export_charset' => 'UTF-8',
260 'default_language' => return_session_value_or_default('default_language',
262 'default_module' => 'Home',
263 'default_password' => '',
264 'default_permissions' => array (
270 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
271 'default_time_format' => 'h:ia',
272 'default_user_is_admin' => false,
273 'default_user_name' => '',
274 'disable_export' => false,
275 'disable_persistent_connections' =>
276 return_session_value_or_default('disable_persistent_connections',
278 'display_email_template_variable_chooser' => false,
279 'display_inbound_email_buttons' => false,
280 'dump_slow_queries' => false,
281 'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
282 'email_default_editor' => 'html',
283 'email_default_client' => 'sugar',
284 'email_default_delete_attachments' => true,
285 'history_max_viewed' => 50,
286 'installer_locked' => true,
287 'import_max_records_per_file' => 100,
288 'import_max_records_total_limit' => '',
289 'languages' => array('en_us' => 'English (US)'),
290 'large_scale_test' => false,
291 'list_max_entries_per_page' => 20,
292 'list_max_entries_per_subpanel' => 10,
293 'lock_default_user_name' => false,
294 'log_memory_usage' => false,
295 'portal_view' => 'single_user',
296 'resource_management' => array (
297 'special_query_limit' => 50000,
298 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
299 'default_limit' => 1000,
301 'require_accounts' => true,
302 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
304 'save_query' => 'all',
305 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
306 'showThemePicker' => true,
307 'slow_query_time_msec' => '100',
309 'time_formats' => array (
310 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
311 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
312 'tracker_max_display_length' => 15,
313 'translation_string_prefix' =>
314 return_session_value_or_default('translation_string_prefix', false),
315 'upload_badext' => array (
316 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
317 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
318 'upload_maxsize' => 30000000,
319 'import_max_execution_time' => 3600,
320 // 'use_php_code_json' => returnPhpJsonStatus(),
321 'verify_client_ip' => true,
322 'js_custom_version' => '',
323 'js_lang_version' => 1,
324 'lead_conv_activity_opt' => 'donothing',
325 'default_number_grouping_seperator' => ',',
326 'default_decimal_seperator' => '.',
327 'lock_homepage' => false,
328 'lock_subpanels' => false,
329 'max_dashlets_homepage' => '15',
330 'default_max_tabs' => '7',
331 'dashlet_display_row_options' => array('1','3','5','10'),
332 'default_subpanel_tabs' => true,
333 'default_subpanel_links' => false,
334 'default_swap_last_viewed' => false,
335 'default_swap_shortcuts' => false,
336 'default_navigation_paradigm' => 'gm',
337 'admin_access_control' => false,
338 'use_common_ml_dir' => false,
339 'common_ml_dir' => '',
342 'default_view' => 'week',
343 'show_calls_by_default' => true,
344 'show_tasks_by_default' => true,
345 'editview_width' => 990,
346 'editview_height' => 480,
347 'day_timestep' => 15,
348 'week_timestep' => 30,
349 'month_timestep' => 60,
350 'items_draggable' => true,
351 'mouseover_expand' => true,
353 'passwordsetting' => empty($passwordsetting) ? array (
354 'SystemGeneratedPasswordON' => '',
355 'generatepasswordtmpl' => '',
356 'lostpasswordtmpl' => '',
357 'forgotpasswordON' => false,
358 'linkexpiration' => '1',
359 'linkexpirationtime' => '30',
360 'linkexpirationtype' => '1',
361 'systexpiration' => '0',
362 'systexpirationtime' => '',
363 'systexpirationtype' => '0',
364 'systexpirationlogin' => '',
365 ) : $passwordsetting,
366 'use_real_names' => true,
367 'search_wildcard_infront' => false,
368 'search_wildcard_char' => '%',
371 if(!is_object($locale)) {
372 $locale = new Localization();
375 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
377 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
378 return( $sugar_config_defaults );
382 * @deprecated use SugarView::getMenu() instead
384 function load_menu($path){
387 if(file_exists($path . 'Menu.php'))
389 require($path . 'Menu.php');
391 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
393 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
395 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
397 require('custom/application/Ext/Menus/menu.ext.php');
403 * get_notify_template_file
404 * This function will return the location of the email notifications template to use
406 * @return string relative file path to email notifications template file
408 function get_notify_template_file($language){
410 * Order of operation:
411 * 1) custom version of specified language
412 * 2) stock version of specified language
413 * 3) custom version of en_us template
414 * 4) stock en_us template
417 // set $file to the base code template so it's set if none of the conditions pass
418 $file = "include/language/en_us.notify_template.html";
420 if(file_exists("custom/include/language/{$language}.notify_template.html")){
421 $file = "custom/include/language/{$language}.notify_template.html";
423 else if(file_exists("include/language/{$language}.notify_template.html")){
424 $file = "include/language/{$language}.notify_template.html";
426 else if(file_exists("custom/include/language/en_us.notify_template.html")){
427 $file = "custom/include/language/en_us.notify_template.html";
433 function sugar_config_union( $default, $override ){
434 // a little different then array_merge and array_merge_recursive. we want
435 // the second array to override the first array if the same value exists,
436 // otherwise merge the unique keys. it handles arrays of arrays recursively
437 // might be suitable for a generic array_union
438 if( !is_array( $override ) ){
441 foreach( $default as $key => $value ){
442 if( !array_key_exists($key, $override) ){
443 $override[$key] = $value;
445 else if( is_array( $key ) ){
446 $override[$key] = sugar_config_union( $value, $override[$key] );
452 function make_not_writable( $file ){
453 // Returns true if the given file/dir has been made not writable
455 if( is_file($file) || is_dir($file) ){
456 if( !is_writable($file) ){
460 $original_fileperms = fileperms($file);
462 // take away writable permissions
463 $new_fileperms = $original_fileperms & ~0x0092;
464 @sugar_chmod($file, $new_fileperms);
466 if( !is_writable($file) ){
475 /** This function returns the name of the person.
476 * It currently returns "first last". It should not put the space if either name is not available.
477 * It should not return errors if either name is not available.
478 * If no names are present, it will return ""
479 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
480 * All Rights Reserved.
481 * Contributor(s): ______________________________________..
483 function return_name($row, $first_column, $last_column)
489 if(isset($row[$first_column]))
491 $first_name = stripslashes($row[$first_column]);
494 if(isset($row[$last_column]))
496 $last_name = stripslashes($row[$last_column]);
499 $full_name = $first_name;
501 // If we have a first name and we have a last name
502 if($full_name != "" && $last_name != "")
504 // append a space, then the last name
505 $full_name .= " ".$last_name;
507 // If we have no first name, but we have a last name
508 else if($last_name != "")
510 // append the last name without the space.
511 $full_name .= $last_name;
518 function get_languages()
520 global $sugar_config;
521 $lang = $sugar_config['languages'];
522 if(!empty($sugar_config['disabled_languages'])){
523 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
524 unset($lang[$disable]);
530 function get_all_languages()
532 global $sugar_config;
533 return $sugar_config['languages'];
537 function get_language_display($key)
539 global $sugar_config;
540 return $sugar_config['languages'][$key];
543 function get_assigned_user_name($assigned_user_id, $is_group = '') {
544 static $saved_user_list = null;
546 if(empty($saved_user_list)) {
547 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
550 if(isset($saved_user_list[$assigned_user_id])) {
551 return $saved_user_list[$assigned_user_id];
558 * retrieves the user_name column value (login)
559 * @param string id GUID of user
562 function get_user_name($id) {
566 $db = DBManagerFactory::getInstance();
568 $q = "SELECT user_name FROM users WHERE id='{$id}'";
570 $a = $db->fetchByAssoc($r);
572 return (empty($a)) ? '' : $a['user_name'];
576 //TODO Update to use global cache
580 * This is a helper function to return an Array of users depending on the parameters passed into the function.
581 * This function uses the get_register_value function by default to use a caching layer where supported.
583 * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
584 * @param string $status String value indicating the status to filter users by, "Active" by default
585 * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
586 * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
587 * @param String $user_name_filter String value indicating the user_name filter (searches the user_name column of users table) to optionally search with, blank by default
588 * @param string $portal_filter String query filter for portal users (defaults to searching non-portal users), change to blank if you wish to search for all users including portal users
589 * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
590 * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
592 function get_user_array($add_blank=true, $status="Active", $user_id='', $use_real_name=false, $user_name_filter='', $portal_filter=' AND portal_only=0 ', $from_cache = true) {
594 global $sugar_config;
597 $locale = new Localization();
601 $key_name = $add_blank. $status . $user_id . $use_real_name . $user_name_filter . $portal_filter;
602 $user_array = get_register_value('user_array', $key_name);
605 if(empty($user_array)) {
606 $db = DBManagerFactory::getInstance();
607 $temp_result = Array();
608 // Including deleted users for now.
609 if (empty($status)) {
610 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$portal_filter;
613 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
616 if (!empty($user_name_filter)) {
617 $query .= " AND user_name LIKE '$user_name_filter%' ";
619 if (!empty($user_id)) {
620 $query .= " OR id='{$user_id}'";
622 $query = $query.' ORDER BY user_name ASC';
623 $GLOBALS['log']->debug("get_user_array query: $query");
624 $result = $db->query($query, true, "Error filling in user array: ");
626 if ($add_blank==true) {
627 // Add in a blank row
628 $temp_result[''] = '';
631 // Get the id and the name.
632 while($row = $db->fetchByAssoc($result)) {
633 if($use_real_name == true || showFullName()) {
634 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
635 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
637 $temp_result[$row['id']] = $row['user_name'];
640 $temp_result[$row['id']] = $row['user_name'];
644 $user_array = $temp_result;
647 set_register_value('user_array', $key_name, $temp_result);
657 * uses a different query to return a list of users than get_user_array()
658 * @param args string where clause entry
659 * @return array Array of Users' details that match passed criteria
661 function getUserArrayFromFullName($args, $hide_portal_users = false) {
663 $db = DBManagerFactory::getInstance();
666 if(strpos($args, " ")) {
667 $argArray = explode(" ", $args);
673 foreach($argArray as $arg) {
674 if(!empty($inClause)) {
680 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
683 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
684 if ( $hide_portal_users ) {
685 $query .= " portal_only=0 AND ";
688 $query .= " ORDER BY last_name ASC";
690 $r = $db->query($query);
692 while($a = $db->fetchByAssoc($r)) {
693 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
701 * based on user pref then system pref
703 function showFullName() {
704 global $sugar_config;
705 global $current_user;
706 static $showFullName = null;
708 if (is_null($showFullName)) {
709 $sysPref = !empty($sugar_config['use_real_names']);
710 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
712 if($userPref != null) {
713 $showFullName = ($userPref == 'on');
715 $showFullName = $sysPref;
719 return $showFullName;
722 function clean($string, $maxLength)
724 $string = substr($string, 0, $maxLength);
725 return escapeshellcmd($string);
729 * Copy the specified request variable to the member variable of the specified object.
730 * Do no copy if the member variable is already set.
731 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
732 * All Rights Reserved.
733 * Contributor(s): ______________________________________..
735 function safe_map($request_var, & $focus, $always_copy = false)
737 safe_map_named($request_var, $focus, $request_var, $always_copy);
741 * Copy the specified request variable to the member variable of the specified object.
742 * Do no copy if the member variable is already set.
743 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
744 * All Rights Reserved.
745 * Contributor(s): ______________________________________..
747 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
749 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
750 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
751 $focus->$member_var = $_REQUEST[$request_var];
756 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
758 * @param string $language specific language to load
759 * @return array lang strings
761 function return_app_list_strings_language($language)
763 global $app_list_strings;
764 global $sugar_config;
766 $cache_key = 'app_list_strings.'.$language;
768 // Check for cached value
769 $cache_entry = sugar_cache_retrieve($cache_key);
770 if(!empty($cache_entry))
775 $default_language = $sugar_config['default_language'];
776 $temp_app_list_strings = $app_list_strings;
779 if ($language != 'en_us') {
782 if ($default_language != 'en_us' && $language != $default_language) {
783 $langs[] = $default_language;
785 $langs[] = $language;
787 $app_list_strings_array = array();
789 foreach ( $langs as $lang ) {
790 $app_list_strings = array();
791 if(file_exists("include/language/$lang.lang.php")) {
792 include("include/language/$lang.lang.php");
793 $GLOBALS['log']->info("Found language file: $lang.lang.php");
795 if(file_exists("include/language/$lang.lang.override.php")) {
796 include("include/language/$lang.lang.override.php");
797 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
799 if(file_exists("include/language/$lang.lang.php.override")) {
800 include("include/language/$lang.lang.php.override");
801 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
804 $app_list_strings_array[] = $app_list_strings;
807 $app_list_strings = array();
808 foreach ( $app_list_strings_array as $app_list_strings_item ) {
809 $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
812 foreach ( $langs as $lang ) {
813 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
814 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
815 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
817 if(file_exists("custom/include/language/$lang.lang.php")) {
818 include("custom/include/language/$lang.lang.php");
819 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
823 if(!isset($app_list_strings)) {
824 $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");
828 $return_value = $app_list_strings;
829 $app_list_strings = $temp_app_list_strings;
831 sugar_cache_put($cache_key, $return_value);
833 return $return_value;
837 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
838 * $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.
839 * @param file string the language that you want include,
840 * @param app_list_strings array the golbal strings
844 function _mergeCustomAppListStrings($file , $app_list_strings){
845 $app_list_strings_original = $app_list_strings;
846 unset($app_list_strings);
847 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
848 // This way, language file can add items to save specific standard codelist from being overwritten
849 $exemptDropdowns = array();
851 if(!isset($app_list_strings) || !is_array($app_list_strings)){
852 return $app_list_strings_original;
854 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
856 // FG - bug 45525 - Specific codelists must NOT be overwritten
857 $exemptDropdowns[] = "moduleList";
858 $exemptDropdowns[] = "parent_type_display";
859 $exemptDropdowns[] = "record_type_display";
860 $exemptDropdowns[] = "record_type_display_notes";
862 foreach($app_list_strings as $key=>$value)
864 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
866 unset($app_list_strings_original["$key"]);
869 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
870 return $app_list_strings;
874 * This function retrieves an application language file and returns the array of strings included.
876 * @param string $language specific language to load
877 * @return array lang strings
879 function return_application_language($language)
881 global $app_strings, $sugar_config;
883 $cache_key = 'app_strings.'.$language;
885 // Check for cached value
886 $cache_entry = sugar_cache_retrieve($cache_key);
887 if(!empty($cache_entry))
892 $temp_app_strings = $app_strings;
893 $default_language = $sugar_config['default_language'];
896 if ($language != 'en_us') {
899 if ($default_language != 'en_us' && $language != $default_language) {
900 $langs[] = $default_language;
903 $langs[] = $language;
905 $app_strings_array = array();
907 foreach ( $langs as $lang ) {
908 $app_strings = array();
909 if(file_exists("include/language/$lang.lang.php")) {
910 include("include/language/$lang.lang.php");
911 $GLOBALS['log']->info("Found language file: $lang.lang.php");
913 if(file_exists("include/language/$lang.lang.override.php")) {
914 include("include/language/$lang.lang.override.php");
915 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
917 if(file_exists("include/language/$lang.lang.php.override")) {
918 include("include/language/$lang.lang.php.override");
919 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
921 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
922 include("custom/application/Ext/Language/$lang.lang.ext.php");
923 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
925 if(file_exists("custom/include/language/$lang.lang.php")) {
926 include("custom/include/language/$lang.lang.php");
927 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
929 $app_strings_array[] = $app_strings;
932 $app_strings = array();
933 foreach ( $app_strings_array as $app_strings_item ) {
934 $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
937 if(!isset($app_strings)) {
938 $GLOBALS['log']->fatal("Unable to load the application language strings");
942 // If we are in debug mode for translating, turn on the prefix now!
943 if($sugar_config['translation_string_prefix']) {
944 foreach($app_strings as $entry_key=>$entry_value) {
945 $app_strings[$entry_key] = $language.' '.$entry_value;
948 if(isset($_SESSION['show_deleted'])) {
949 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
950 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
951 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
952 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
955 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
957 $return_value = $app_strings;
958 $app_strings = $temp_app_strings;
960 sugar_cache_put($cache_key, $return_value);
962 return $return_value;
966 * This function retrieves a module's language file and returns the array of strings included.
968 * @param string $language specific language to load
969 * @param string $module module name to load strings for
970 * @param bool $refresh optional, true if you want to rebuild the language strings
971 * @return array lang strings
973 function return_module_language($language, $module, $refresh=false)
976 global $sugar_config;
977 global $currentModule;
979 // Jenny - Bug 8119: Need to check if $module is not empty
980 if (empty($module)) {
981 $stack = debug_backtrace();
982 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
988 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
989 // Check for cached value
990 $cache_entry = sugar_cache_retrieve($cache_key);
991 if(!empty($cache_entry))
996 // Store the current mod strings for later
997 $temp_mod_strings = $mod_strings;
998 $loaded_mod_strings = array();
999 $language_used = $language;
1000 $default_language = $sugar_config['default_language'];
1002 if(empty($language)) {
1003 $language = $default_language;
1006 // Bug 21559 - So we can get all the strings defined in the template, refresh
1007 // the vardefs file if the cached language file doesn't exist.
1008 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1009 && !empty($GLOBALS['beanList'][$module])){
1010 $object = BeanFactory::getObjectName($module);
1011 VardefManager::refreshVardefs($module,$object);
1014 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1016 // cn: bug 6048 - merge en_us with requested language
1017 if($language != $sugar_config['default_language'])
1018 $loaded_mod_strings = sugarArrayMerge(
1019 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1023 // Load in en_us strings by default
1024 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1025 $loaded_mod_strings = sugarArrayMerge(
1026 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1030 // If we are in debug mode for translating, turn on the prefix now!
1031 if($sugar_config['translation_string_prefix']) {
1032 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1033 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1037 $return_value = $loaded_mod_strings;
1038 if(!isset($mod_strings)){
1039 $mod_strings = $return_value;
1042 $mod_strings = $temp_mod_strings;
1044 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1045 sugar_cache_put($cache_key, $return_value);
1046 return $return_value;
1050 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1051 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1052 * All Rights Reserved.
1053 * Contributor(s): ______________________________________..
1054 * If you are using the current language, do not call this function unless you are loading it for the first time */
1055 function return_mod_list_strings_language($language,$module) {
1056 global $mod_list_strings;
1057 global $sugar_config;
1058 global $currentModule;
1060 $cache_key = "mod_list_str_lang.".$language.$module;
1062 // Check for cached value
1063 $cache_entry = sugar_cache_retrieve($cache_key);
1064 if(!empty($cache_entry))
1066 return $cache_entry;
1069 $language_used = $language;
1070 $temp_mod_list_strings = $mod_list_strings;
1071 $default_language = $sugar_config['default_language'];
1073 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1074 return $mod_list_strings;
1077 // cn: bug 6351 - include en_us if file langpack not available
1078 // cn: bug 6048 - merge en_us with requested language
1079 include("modules/$module/language/en_us.lang.php");
1080 $en_mod_list_strings = array();
1081 if($language_used != $default_language)
1082 $en_mod_list_strings = $mod_list_strings;
1084 if(file_exists("modules/$module/language/$language.lang.php")) {
1085 include("modules/$module/language/$language.lang.php");
1088 if(file_exists("modules/$module/language/$language.lang.override.php")){
1089 include("modules/$module/language/$language.lang.override.php");
1092 if(file_exists("modules/$module/language/$language.lang.php.override")){
1093 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1094 include("modules/$module/language/$language.lang.php.override");
1097 // cn: bug 6048 - merge en_us with requested language
1098 $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1100 // if we still don't have a language pack, then log an error
1101 if(!isset($mod_list_strings)) {
1102 $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})");
1106 $return_value = $mod_list_strings;
1107 $mod_list_strings = $temp_mod_list_strings;
1109 sugar_cache_put($cache_key, $return_value);
1110 return $return_value;
1114 /** This function retrieves a theme's language file and returns the array of strings included.
1115 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1116 * All Rights Reserved.
1117 * Contributor(s): ______________________________________..
1119 function return_theme_language($language, $theme)
1121 global $mod_strings, $sugar_config, $current_language;
1123 $language_used = $language;
1124 $default_language = $sugar_config['default_language'];
1126 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1127 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1128 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1130 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1131 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";
1132 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1134 if(!isset($theme_strings))
1136 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1137 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1138 $language_used = $default_language;
1141 if(!isset($theme_strings))
1143 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1147 // If we are in debug mode for translating, turn on the prefix now!
1148 if($sugar_config['translation_string_prefix'])
1150 foreach($theme_strings as $entry_key=>$entry_value)
1152 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1156 return $theme_strings;
1161 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1162 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1163 * All Rights Reserved.
1164 * Contributor(s): ______________________________________..
1166 function return_session_value_or_default($varname, $default)
1168 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1170 return $_SESSION[$varname];
1177 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1178 * 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.
1179 * @param &$where_clauses - The array to append the clause to
1180 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1181 * @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.
1182 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1183 * All Rights Reserved.
1184 * Contributor(s): ______________________________________..
1186 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1188 if($SQL_name == null)
1190 $SQL_name = $variable_name;
1193 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1195 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1200 * Generate the appropriate SQL based on the where clauses.
1201 * @param $where_clauses - An Array of individual where clauses stored as strings
1202 * @returns string where_clause - The final SQL where clause to be executed.
1203 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1204 * All Rights Reserved.
1205 * Contributor(s): ______________________________________..
1207 function generate_where_statement($where_clauses)
1210 foreach($where_clauses as $clause)
1217 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1222 * determines if a passed string matches the criteria for a Sugar GUID
1223 * @param string $guid
1224 * @return bool False on failure
1226 function is_guid($guid) {
1227 if(strlen($guid) != 36) {
1231 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1240 * A temporary method of generating GUIDs of the correct format for our DB.
1241 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1243 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1244 * All Rights Reserved.
1245 * Contributor(s): ______________________________________..
1247 function create_guid()
1249 $microTime = microtime();
1250 list($a_dec, $a_sec) = explode(" ", $microTime);
1252 $dec_hex = dechex($a_dec* 1000000);
1253 $sec_hex = dechex($a_sec);
1255 ensure_length($dec_hex, 5);
1256 ensure_length($sec_hex, 6);
1260 $guid .= create_guid_section(3);
1262 $guid .= create_guid_section(4);
1264 $guid .= create_guid_section(4);
1266 $guid .= create_guid_section(4);
1269 $guid .= create_guid_section(6);
1275 function create_guid_section($characters)
1278 for($i=0; $i<$characters; $i++)
1280 $return .= dechex(mt_rand(0,15));
1285 function ensure_length(&$string, $length)
1287 $strlen = strlen($string);
1288 if($strlen < $length)
1290 $string = str_pad($string,$length,"0");
1292 else if($strlen > $length)
1294 $string = substr($string, 0, $length);
1298 function microtime_diff($a, $b) {
1299 list($a_dec, $a_sec) = explode(" ", $a);
1300 list($b_dec, $b_sec) = explode(" ", $b);
1301 return $b_sec - $a_sec + $b_dec - $a_dec;
1304 // check if Studio is displayed.
1305 function displayStudioForCurrentUser()
1307 global $current_user;
1308 if ( $current_user->isAdmin() ) {
1318 function displayWorkflowForCurrentUser()
1320 $_SESSION['display_workflow_for_user'] = false;
1324 // return an array with all modules where the user is an admin.
1325 function get_admin_modules_for_user($user) {
1326 $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");
1333 return($user->getDeveloperModules());
1337 function get_workflow_admin_modules_for_user($user){
1338 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1339 return $_SESSION['get_workflow_admin_modules_for_user'];
1343 $workflow_mod_list = array();
1344 foreach($moduleList as $module){
1345 $workflow_mod_list[$module] = $module;
1348 // This list is taken from teh previous version of workflow_utils.php
1349 $workflow_mod_list['Tasks'] = "Tasks";
1350 $workflow_mod_list['Calls'] = "Calls";
1351 $workflow_mod_list['Meetings'] = "Meetings";
1352 $workflow_mod_list['Notes'] = "Notes";
1353 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1354 $workflow_mod_list['Leads'] = "Leads";
1355 $workflow_mod_list['Opportunities'] = "Opportunities";
1358 $workflow_admin_modules = array();
1360 return $workflow_admin_modules;
1362 $actions = ACLAction::getUserActions($user->id);
1363 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1364 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1365 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1366 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1368 foreach ($workflow_mod_list as $key=>$val) {
1369 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1370 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1371 ($user->isDeveloperForModule($key))) {
1372 $workflow_admin_modules[$key] = $val;
1375 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1376 return ($workflow_admin_modules);
1379 // Check if user is admin for at least one module.
1380 function is_admin_for_any_module($user) {
1384 if($user->isAdmin()) {
1391 // Check if user is admin for a specific module.
1392 function is_admin_for_module($user,$module) {
1393 if (!isset($user)) {
1396 if ($user->isAdmin()) {
1404 * Check if user id belongs to a system admin.
1405 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1406 * All Rights Reserved.
1407 * Contributor(s): ______________________________________..
1409 function is_admin($user) {
1414 return $user->isAdmin();
1418 * Return the display name for a theme if it exists.
1419 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1420 * All Rights Reserved.
1421 * Contributor(s): ______________________________________..
1423 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1425 function get_theme_display($theme)
1427 return SugarThemeRegistry::get($theme)->name;
1431 * Return an array of directory names.
1432 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1433 * All Rights Reserved.
1434 * Contributor(s): ______________________________________..
1436 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1438 function get_themes()
1440 return SugarThemeRegistry::availableThemes();
1444 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1445 * Create HTML to display select options in a dropdown list. To be used inside
1446 * of a select statement in a form.
1447 * param $option_list - the array of strings to that contains the option list
1448 * param $selected - the string which contains the default value
1449 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1450 * All Rights Reserved.
1451 * Contributor(s): ______________________________________..
1453 function get_select_options ($option_list, $selected) {
1454 return get_select_options_with_id($option_list, $selected);
1458 * Create HTML to display select options in a dropdown list. To be used inside
1459 * 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.
1460 * param $option_list - the array of strings to that contains the option list
1461 * param $selected - the string which contains the default value
1462 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1463 * All Rights Reserved.
1464 * Contributor(s): ______________________________________..
1466 function get_select_options_with_id ($option_list, $selected_key) {
1467 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1472 * Create HTML to display select options in a dropdown list. To be used inside
1473 * 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.
1474 * param $label_list - the array of strings to that contains the option list
1475 * param $key_list - the array of strings to that contains the values list
1476 * param $selected - the string which contains the default value
1477 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1478 * All Rights Reserved.
1479 * Contributor(s): ______________________________________..
1481 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1482 global $app_strings;
1483 $select_options = "";
1485 //for setting null selection values to human readable --None--
1486 $pattern = "/'0?'></";
1487 $replacement = "''>".$app_strings['LBL_NONE']."<";
1489 $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
1492 if (empty($key_list)) $key_list = array();
1493 //create the type dropdown domain and set the selected value if $opp value already exists
1494 foreach ($key_list as $option_key=>$option_value) {
1496 $selected_string = '';
1497 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1498 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1499 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1501 $selected_string = 'selected ';
1504 $html_value = $option_key;
1506 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1508 $select_options = preg_replace($pattern, $replacement, $select_options);
1509 return $select_options;
1514 * Call this method instead of die().
1515 * Then we call the die method with the error message that is passed in.
1517 function sugar_die($error_message)
1521 die($error_message);
1526 * Create javascript to clear values of all elements in a form.
1527 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1528 * All Rights Reserved.
1529 * Contributor(s): ______________________________________..
1531 function get_clear_form_js () {
1532 $the_script = <<<EOQ
1533 <script type="text/javascript" language="JavaScript">
1534 function clear_form(form) {
1535 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1536 if(typeof(form.advanced) != 'undefined'){
1537 newLoc += '&advanced=' + form.advanced.value;
1539 document.location.href= newLoc;
1548 * Create javascript to set the cursor focus to specific field in a form
1549 * when the screen is rendered. The field name is currently hardcoded into the
1551 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1552 * All Rights Reserved.
1553 * Contributor(s): ______________________________________..
1555 function get_set_focus_js () {
1556 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1557 $the_script = <<<EOQ
1558 <script type="text/javascript" language="JavaScript">
1560 function set_focus() {
1561 if (document.forms.length > 0) {
1562 for (i = 0; i < document.forms.length; i++) {
1563 for (j = 0; j < document.forms[i].elements.length; j++) {
1564 var field = document.forms[i].elements[j];
1565 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1566 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1568 if (field.type == "text") {
1585 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1586 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1587 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1588 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1589 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1590 * the first - so the array is sorted by the last given column first, then the one before ...
1591 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1592 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1593 * All Rights Reserved.
1594 * Contributor(s): ______________________________________..
1596 function array_csort() {
1597 $args = func_get_args();
1598 $marray = array_shift($args);
1601 $msortline = "return(array_multisort(";
1602 foreach ($args as $arg) {
1604 if (is_string($arg)) {
1605 foreach ($marray as $row) {
1606 $sortarr[$i][] = $row[$arg];
1609 $sortarr[$i] = $arg;
1611 $msortline .= "\$sortarr[".$i."],";
1613 $msortline .= "\$marray));";
1620 * Converts localized date format string to jscalendar format
1621 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1622 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1623 * All Rights Reserved.
1624 * Contributor(s): ______________________________________..
1626 function parse_calendardate($local_format) {
1627 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1628 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1629 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1636 function translate($string, $mod='', $selectedValue=''){
1637 //$test_start = microtime();
1638 //static $mod_strings_results = array();
1640 global $current_language;
1642 if(isset($_REQUEST['login_language'])){
1643 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1645 $mod_strings = return_module_language($current_language, $mod);
1648 global $mod_strings;
1652 global $app_strings, $app_list_strings;
1654 if(isset($mod_strings[$string]))
1655 $returnValue = $mod_strings[$string];
1656 else if(isset($app_strings[$string]))
1657 $returnValue = $app_strings[$string];
1658 else if(isset($app_list_strings[$string]))
1659 $returnValue = $app_list_strings[$string];
1660 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1661 $returnValue = $app_list_strings['moduleList'][$string];
1664 //$test_end = microtime();
1666 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1668 // echo("translate results:");
1670 // $total_strings = 0;
1671 // foreach($mod_strings_results as $key=>$value)
1673 // echo("Module $key \t\t time $value \t\t<br>");
1674 // $total_time += $value;
1677 // echo("Total time: $total_time<br>");
1681 if(empty($returnValue)){
1685 if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1686 return $returnValue[$selectedValue];
1689 return $returnValue;
1692 function unTranslateNum($num) {
1694 static $num_grp_sep;
1695 global $current_user, $sugar_config;
1697 if($dec_sep == null) {
1698 $user_dec_sep = $current_user->getPreference('dec_sep');
1699 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1701 if($num_grp_sep == null) {
1702 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1703 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1706 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1707 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1712 function add_http($url) {
1713 if(!preg_match("@://@i", $url)) {
1715 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1719 return "{$scheme}://{$url}";
1726 * returns a default array of XSS tags to clean
1729 function getDefaultXssTags() {
1731 "applet" => "applet",
1736 "frameset" => "frameset",
1737 "iframe" => "iframe",
1738 "import" => "\?import",
1741 "object" => "object",
1742 "script" => "script",
1746 $ret = base64_encode(serialize($tmp));
1752 * Remove potential xss vectors from strings
1753 * @param string str String to search for XSS attack vectors
1754 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1757 function remove_xss($str, $cleanImg=true)
1759 $potentials = clean_xss($str, $cleanImg);
1760 if(is_array($potentials) && !empty($potentials)) {
1761 foreach($potentials as $bad) {
1762 $str = str_replace($bad, "", $str);
1769 * Detects typical XSS attack patterns
1770 * @param string str String to search for XSS attack vectors
1771 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1772 * @return array Array of matches, empty on clean string
1774 function clean_xss($str, $cleanImg=true) {
1775 global $sugar_config;
1777 if(empty($sugar_config['email_xss']))
1778 $sugar_config['email_xss'] = getDefaultXssTags();
1780 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1782 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1783 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1784 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1785 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1787 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1788 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1789 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1790 $css_url = '#url\(.*\.\w+\)#';
1792 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1794 $tagmatches = array();
1796 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1797 foreach($tagmatches[1] as $no => $tag) {
1798 if(in_array($tag, $xsstags)) {
1799 // dangerous tag - take out whole
1800 $matches[] = $tagmatches[0][$no];
1803 $attrmatch = array();
1804 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1805 if(!empty($attrmatch[0])) {
1806 $matches = array_merge($matches, $attrmatch[0]);
1810 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1813 $matches = array_merge($matches,
1814 xss_check_pattern($imgsrc_regex, $str)
1818 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1819 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1821 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1822 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1823 // normalize whitelist
1824 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1825 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1828 foreach($cssUrlMatches[0] as $match) {
1829 $domain = strtolower(substr(strstr($match, "://"), 3));
1830 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1832 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1833 $matches[] = $match;
1838 $matches = array_merge($matches, $cssUrlMatches[0]);
1845 * Helper function used by clean_xss() to parse for known-bad vectors
1846 * @param string pattern Regex pattern to use
1847 * @param string str String to parse for badness
1850 function xss_check_pattern($pattern, $str) {
1851 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1856 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1858 * @param string $str
1859 * @param string $filter which corresponds to a regular expression to use; choices are:
1860 * "STANDARD" ( default )
1870 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1872 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1874 global $sugar_config;
1877 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1878 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1879 "FILE" => '#[^A-Z0-9\-_\.]#i',
1880 "NUMBER" => '#[^0-9\-]#i',
1881 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1882 "PATH_NO_URL" => '#://#i',
1883 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1884 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1885 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1886 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1889 if (preg_match($filters[$filter], $str)) {
1890 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1891 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1893 if ( $dieOnBadData ) {
1894 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1903 function clean_special_arguments() {
1904 if(isset($_SERVER['PHP_SELF'])) {
1905 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1907 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1908 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1909 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1910 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1911 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1912 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1913 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1914 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1915 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1916 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1917 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1918 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1919 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1920 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1921 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1922 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1923 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1924 clean_superglobals('offset', 'ALPHANUM');
1925 clean_superglobals('return_action');
1926 clean_superglobals('return_module');
1931 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1933 function clean_superglobals($key, $filter = 'STANDARD') {
1934 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1935 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1936 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1939 function set_superglobals($key, $val){
1941 $_POST[$key] = $val;
1942 $_REQUEST[$key] = $val;
1945 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1946 function clean_incoming_data() {
1947 global $sugar_config;
1948 global $RAW_REQUEST;
1950 if(get_magic_quotes_gpc()) {
1951 // magic quotes screw up data, we'd have to clean up
1952 $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1954 $RAW_REQUEST = $_REQUEST;
1957 if (get_magic_quotes_gpc() == 1) {
1958 $req = array_map("preprocess_param", $_REQUEST);
1959 $post = array_map("preprocess_param", $_POST);
1960 $get = array_map("preprocess_param", $_GET);
1963 $req = array_map("securexss", $_REQUEST);
1964 $post = array_map("securexss", $_POST);
1965 $get = array_map("securexss", $_GET);
1968 // PHP cannot stomp out superglobals reliably
1969 foreach($post as $k => $v) { $_POST[$k] = $v; }
1970 foreach($get as $k => $v) { $_GET[$k] = $v; }
1971 foreach($req as $k => $v) {
1973 //ensure the keys are safe as well
1976 // Any additional variables that need to be cleaned should be added here
1977 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1978 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1979 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1980 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1981 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1982 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
1983 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
1984 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
1985 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
1986 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
1987 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
1988 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
1989 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
1991 if(isset($_REQUEST['lvso'])){
1992 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
1994 // Clean "offset" and "order_by" parameters in URL
1995 foreach ($_REQUEST as $key => $val) {
1996 if (str_end($key, "_offset")) {
1997 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
1998 set_superglobals($key, $_REQUEST[$key]);
2000 elseif (str_end($key, "_ORDER_BY")) {
2001 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2002 set_superglobals($key, $_REQUEST[$key]);
2010 // Returns TRUE if $str begins with $begin
2011 function str_begin($str, $begin) {
2012 return (substr($str, 0, strlen($begin)) == $begin);
2015 // Returns TRUE if $str ends with $end
2016 function str_end($str, $end) {
2017 return (substr($str, strlen($str) - strlen($end)) == $end);
2020 function securexss($value) {
2021 if(is_array($value)){
2023 foreach($value as $key=>$val){
2024 $new[$key] = securexss($val);
2028 static $xss_cleanup= array(""" => "&", '"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2029 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2030 $value = preg_replace('/javascript:/i', 'java script:', $value);
2031 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2034 function securexsskey($value, $die=true){
2035 global $sugar_config;
2037 preg_match('/[\'"<>]/', $value, $matches);
2038 if(!empty($matches)){
2040 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2042 unset($_REQUEST[$value]);
2043 unset($_POST[$value]);
2044 unset($_GET[$value]);
2049 function preprocess_param($value){
2050 if(is_string($value)){
2051 if(get_magic_quotes_gpc() == 1){
2052 $value = stripslashes($value);
2055 $value = securexss($value);
2061 function cleanup_slashes($value)
2063 if(is_string($value)) return stripslashes($value);
2068 function set_register_value($category, $name, $value){
2069 return sugar_cache_put("{$category}:{$name}", $value);
2072 function get_register_value($category,$name){
2073 return sugar_cache_retrieve("{$category}:{$name}");
2076 function clear_register_value($category,$name){
2077 return sugar_cache_clear("{$category}:{$name}");
2079 // this function cleans id's when being imported
2080 function convert_id($string)
2082 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2084 // single quotes are essential here,
2085 // or alternative escape all $ as \$
2087 'return ord($matches[0]);'
2092 * @deprecated use SugarTheme::getImage()
2094 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2096 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2099 * @deprecated use SugarTheme::getImageURL()
2101 function getImagePath($image_name)
2103 return SugarThemeRegistry::current()->getImageURL($image_name);
2106 function getWebPath($relative_path){
2107 //if it has a :// then it isn't a relative path
2108 if(substr_count($relative_path, '://') > 0) return $relative_path;
2109 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2110 return $relative_path;
2113 function getVersionedPath($path, $additional_attrs='')
2115 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2116 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2117 if(inDeveloperMode()) {
2119 if(empty($rand)) $rand = mt_rand();
2124 if(is_array($additional_attrs)) {
2125 $additional_attrs = join("|",$additional_attrs);
2127 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2128 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2129 // remove / - it confuses some parsers
2130 $str = strtr($str, '/+', '-_');
2131 if(empty($path)) return $str;
2133 return $path . "?v=$str";
2136 function getVersionedScript($path, $additional_attrs='')
2138 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2141 function getJSPath($relative_path, $additional_attrs='')
2143 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2144 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2147 function getSWFPath($relative_path, $additional_params=''){
2148 $path = $relative_path;
2149 if (!empty($additional_params)){
2150 $path .= '?' . $additional_params;
2152 if (defined('TEMPLATE_URL')){
2153 $path = TEMPLATE_URL . '/' . $path;
2162 function getSQLDate($date_str)
2164 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2166 if ( strlen($match[2]) == 1)
2168 $match[2] = "0".$match[2];
2170 if ( strlen($match[1]) == 1)
2172 $match[1] = "0".$match[1];
2174 return "{$match[3]}-{$match[1]}-{$match[2]}";
2176 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2178 if ( strlen($match[2]) == 1)
2180 $match[2] = "0".$match[2];
2182 if ( strlen($match[1]) == 1)
2184 $match[1] = "0".$match[1];
2186 return "{$match[3]}-{$match[1]}-{$match[2]}";
2194 function clone_history(&$db, $from_id,$to_id, $to_type)
2199 require_once('include/upload_file.php');
2200 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2202 $location=array('Email'=>"modules/Emails/Email.php",
2203 'Call'=>"modules/Calls/Call.php",
2204 'Meeting'=>"modules/Meetings/Meeting.php",
2205 'Note'=>"modules/Notes/Note.php",
2206 'Tasks'=>"modules/Tasks/Task.php",
2210 foreach($tables as $table=>$bean_class)
2213 if (!class_exists($bean_class))
2215 require_once($location[$bean_class]);
2218 $bProcessingNotes=false;
2219 if ($table=='notes')
2221 $bProcessingNotes=true;
2223 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2224 $results = $db->query($query);
2225 while($row = $db->fetchByAssoc($results))
2227 //retrieve existing record.
2228 $bean= new $bean_class();
2229 $bean->retrieve($row['id']);
2230 //process for new instance.
2231 if ($bProcessingNotes)
2233 $old_note_id=$row['id'];
2234 $old_filename=$bean->filename;
2237 $bean->parent_id=$to_id;
2238 $bean->parent_type=$to_type;
2239 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2241 $bean->contact_id=$to_id;
2243 $bean->update_date_modified = false;
2244 $bean->update_modified_by = false;
2245 if(isset($bean->date_modified))
2246 $bean->date_modified = $timedate->to_db($bean->date_modified);
2247 if(isset($bean->date_entered))
2248 $bean->date_entered = $timedate->to_db($bean->date_entered);
2250 $new_id=$bean->save();
2252 //duplicate the file now. for notes.
2253 if ($bProcessingNotes && !empty($old_filename))
2255 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2257 //reset the values needed for attachment duplication.
2264 function values_to_keys($array)
2266 $new_array = array();
2267 if(!is_array($array))
2271 foreach($array as $arr){
2272 $new_array[$arr] = $arr;
2277 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2279 foreach($tables as $table)
2282 if ($table == 'emails_beans') {
2283 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2285 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2287 $results = $db->query($query);
2288 while($row = $db->fetchByAssoc($results))
2290 $query = "INSERT INTO $table ";
2293 $row[$from_column] = $to_id;
2294 $row['id'] = create_guid();
2295 if ($table=='emails_beans') {
2296 $row['bean_module'] =='Contacts';
2299 foreach($row as $name=>$value)
2305 $values .= "'$value'";
2308 $names .= ', '. $name;
2309 $values .= ", '$value'";
2312 $query .= "($names) VALUES ($values)";
2318 function get_unlinked_email_query($type, $bean) {
2319 global $current_user;
2321 $return_array['select']='SELECT emails.id ';
2322 $return_array['from']='FROM emails ';
2323 $return_array['where']="";
2324 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2326 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2327 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2328 where eear.deleted=0 and eear.email_id not in
2329 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2330 ) derivedemails on derivedemails.email_id = emails.id";
2331 $return_array['join_tables'][0] = '';
2333 if (isset($type) and !empty($type['return_as_array'])) {
2334 return $return_array;
2337 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2341 * Check to see if the number is empty or non-zero
2345 function number_empty($value)
2347 return empty($value) && $value != '0';
2350 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2353 require_once($beanFiles[$bean_name]);
2354 $focus = new $bean_name();
2355 $user_array = array();
2357 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2358 $user_array = get_register_value('select_array', $key );
2362 $db = DBManagerFactory::getInstance();
2364 $temp_result = Array();
2365 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2369 $query .= $where." AND ";
2372 $query .= " {$focus->table_name}.deleted=0";
2374 if ( $order_by != '')
2376 $query .= " order by {$focus->table_name}.{$order_by}";
2379 $GLOBALS['log']->debug("get_user_array query: $query");
2380 $result = $db->query($query, true, "Error filling in user array: ");
2382 if ($add_blank==true){
2383 // Add in a blank row
2384 if($blank_is_none == true) { // set 'blank row' to "--None--"
2385 global $app_strings;
2386 $temp_result[''] = $app_strings['LBL_NONE'];
2388 $temp_result[''] = '';
2392 // Get the id and the name.
2393 while($row = $db->fetchByAssoc($result))
2395 $temp_result[$row['id']] = $row['display'];
2398 $user_array = $temp_result;
2399 set_register_value('select_array', $key ,$temp_result);
2408 * @param unknown_type $listArray
2410 // function parse_list_modules
2411 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2412 function parse_list_modules(&$listArray)
2414 global $modListHeader;
2415 $returnArray = array();
2417 foreach($listArray as $optionName => $optionVal)
2419 if(array_key_exists($optionName, $modListHeader))
2421 $returnArray[$optionName] = $optionVal;
2424 // special case for projects
2425 if(array_key_exists('Project', $modListHeader))
2427 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2430 $acldenied = ACLController::disabledModuleList($listArray,false);
2431 foreach($acldenied as $denied){
2432 unset($returnArray[$denied]);
2434 asort($returnArray);
2436 return $returnArray;
2439 function display_notice($msg = false){
2440 global $error_notice;
2441 //no error notice - lets just display the error to the user
2442 if(!isset($error_notice)){
2443 echo '<br>'.$msg . '<br>';
2445 $error_notice .= $msg . '<br>';
2449 /* checks if it is a number that atleast has the plus at the beggining
2451 function skype_formatted($number){
2452 //kbrill - BUG #15375
2453 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2456 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2458 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2461 function format_skype($number) {
2462 return preg_replace('/[^\+0-9]/','',$number);
2465 function insert_charset_header() {
2466 header('Content-Type: text/html; charset=UTF-8');
2469 function getCurrentURL()
2472 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2477 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2481 function javascript_escape($str) {
2484 for($i = 0; $i < strlen($str); $i++) {
2486 if(ord(substr($str, $i, 1))==10){
2488 }elseif(ord(substr($str, $i, 1))==13){
2492 $new_str .= $str{$i};
2496 $new_str = str_replace("'", "\\'", $new_str);
2501 function js_escape($str, $keep=true){
2502 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2505 $str = javascript_escape($str);
2508 $str = str_replace("'", " ", $str);
2509 $str = str_replace('"', " ", $str);
2514 //end function js_escape
2517 function br2nl($str) {
2518 $regex = "#<[^>]+br.+?>#i";
2519 preg_match_all($regex, $str, $matches);
2521 foreach($matches[0] as $match) {
2522 $str = str_replace($match, "<br>", $str);
2525 $brs = array('<br>','<br/>', '<br />');
2526 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2527 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2528 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2529 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2535 * Private helper function for displaying the contents of a given variable.
2536 * This function is only intended to be used for SugarCRM internal development.
2537 * The ppd stands for Pre Print Die.
2539 function _ppd($mixed)
2545 * Private helper function for displaying the contents of a given variable in
2546 * the Logger. This function is only intended to be used for SugarCRM internal
2547 * development. The pp stands for Pre Print.
2548 * @param $mixed var to print_r()
2549 * @param $die boolean end script flow
2550 * @param $displayStackTrace also show stack trace
2552 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2553 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2555 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2559 $mix = print_r($mixed, true); // send print_r() output to $mix
2560 $stack = debug_backtrace();
2562 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2563 $GLOBALS['log']->$loglevel($mix);
2564 if($displayStackTrace) {
2565 foreach($stack as $position) {
2566 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2570 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2571 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2579 * private helper function to quickly show the major, direct, field attributes of a given bean.
2580 * The ppf stands for Pre[formatted] Print Focus [object]
2581 * @param object bean The focus bean
2583 function _ppf($bean, $die=false) {
2589 * Private helper function for displaying the contents of a given variable.
2590 * This function is only intended to be used for SugarCRM internal development.
2591 * The pp stands for Pre Print.
2593 function _pp($mixed)
2598 * Private helper function for displaying the contents of a given variable.
2599 * This function is only intended to be used for SugarCRM internal development.
2600 * The pp stands for Pre Print.
2602 function _pstack_trace($mixed=NULL)
2607 * Private helper function for displaying the contents of a given variable.
2608 * This function is only intended to be used for SugarCRM internal development.
2609 * The pp stands for Pre Print Trace.
2611 function _ppt($mixed, $textOnly=false)
2616 * Private helper function for displaying the contents of a given variable.
2617 * This function is only intended to be used for SugarCRM internal development.
2618 * The pp stands for Pre Print Trace Die.
2620 function _pptd($mixed)
2625 * Private helper function for decoding javascript UTF8
2626 * This function is only intended to be used for SugarCRM internal development.
2628 function decodeJavascriptUTF8($str) {
2632 * Will check if a given PHP version string is supported (tested on this ver),
2633 * unsupported (results unknown), or invalid (something will break on this
2634 * ver). Do not pass in any pararameter to default to a check against the
2635 * current environment's PHP version.
2637 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2639 function check_php_version($sys_php_version = '') {
2640 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2641 // versions below $min_considered_php_version considered invalid by default,
2642 // versions equal to or above this ver will be considered depending
2643 // on the rules that follow
2644 $min_considered_php_version = '5.2.1';
2646 // only the supported versions,
2647 // should be mutually exclusive with $invalid_php_versions
2648 $supported_php_versions = array (
2649 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2652 // invalid versions above the $min_considered_php_version,
2653 // should be mutually exclusive with $supported_php_versions
2655 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2656 $invalid_php_versions = array('5.2.7');
2658 // default unsupported
2661 // versions below $min_considered_php_version are invalid
2662 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2666 // supported version check overrides default unsupported
2667 foreach($supported_php_versions as $ver) {
2668 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2674 // invalid version check overrides default unsupported
2675 foreach($invalid_php_versions as $ver) {
2676 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2682 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2683 //and the php version contains 'rh' characters
2684 if(strpos($sys_php_version, 'rh') !== false) {
2692 * Will check if a given IIS version string is supported (tested on this ver),
2693 * unsupported (results unknown), or invalid (something will break on this
2696 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2698 function check_iis_version($sys_iis_version = '') {
2700 $server_software = $_SERVER["SERVER_SOFTWARE"];
2702 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2703 $iis_version = $out[1][0];
2705 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2707 // versions below $min_considered_iis_version considered invalid by default,
2708 // versions equal to or above this ver will be considered depending
2709 // on the rules that follow
2710 $min_considered_iis_version = '6.0';
2712 // only the supported versions,
2713 // should be mutually exclusive with $invalid_iis_versions
2714 $supported_iis_versions = array ('6.0', '7.0',);
2715 $unsupported_iis_versions = array();
2716 $invalid_iis_versions = array('5.0',);
2718 // default unsupported
2721 // versions below $min_considered_iis_version are invalid
2722 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2726 // supported version check overrides default unsupported
2727 foreach($supported_iis_versions as $ver) {
2728 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2734 // unsupported version check overrides default unsupported
2735 foreach($unsupported_iis_versions as $ver) {
2736 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2742 // invalid version check overrides default unsupported
2743 foreach($invalid_iis_versions as $ver) {
2744 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2753 function pre_login_check(){
2754 global $action, $login_error;
2755 if(!empty($action)&& $action == 'Login'){
2757 if(!empty($login_error)){
2758 $login_error = htmlentities($login_error);
2759 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2760 $_SESSION['login_error'] = $login_error;
2762 function set_focus() {}
2763 if(document.getElementById("post_error")) {
2764 document.getElementById("post_error").innerHTML="'. $login_error. '";
2765 document.getElementById("cant_login").value=1;
2766 document.getElementById("login_button").disabled = true;
2767 document.getElementById("user_name").disabled = true;
2768 //document.getElementById("user_password").disabled = true;
2777 function sugar_cleanup($exit = false) {
2778 static $called = false;
2781 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2782 chdir(realpath(dirname(__FILE__) . '/..'));
2783 global $sugar_config;
2784 require_once('include/utils/LogicHook.php');
2785 LogicHook::initialize();
2786 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2788 //added this check to avoid errors during install.
2789 if (empty($sugar_config['dbconfig'])) {
2790 if ($exit) exit; else return;
2793 if (!class_exists('Tracker', true)) {
2794 require_once 'modules/Trackers/Tracker.php';
2797 // Now write the cached tracker_queries
2798 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2799 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2800 $GLOBALS['current_user']->savePreferencesToDB();
2803 //check to see if this is not an `ajax call AND the user preference error flag is set
2805 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2806 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2807 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2808 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2811 global $app_strings;
2812 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2813 $err_mess = $app_strings['ERROR_USER_PREFS'];
2814 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2817 ajaxStatus.flashStatus('$err_mess',7000);
2823 if(class_exists('DBManagerFactory')) {
2824 $db = DBManagerFactory::getInstance();
2832 register_shutdown_function('sugar_cleanup');
2836 check_logic_hook - checks to see if your custom logic is in the logic file
2837 if not, it will add it. If the file isn't built yet, it will create the file
2840 function check_logic_hook_file($module_name, $event, $action_array){
2841 require_once('include/utils/logic_utils.php');
2844 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2846 $hook_array = get_hook_array($module_name);
2848 if(check_existing_element($hook_array, $event, $action_array)==true){
2849 //the hook at hand is present, so do nothing
2854 if(!empty($hook_array[$event]))
2856 $logic_count = count($hook_array[$event]);
2859 if($action_array[0]==""){
2860 $action_array[0] = $logic_count + 1;
2862 $hook_array[$event][] = $action_array;
2865 //end if the file exists already
2868 if($action_array[0]==""){
2869 $action_array[0] = 1;
2871 $hook_array = array();
2872 $hook_array[$event][] = $action_array;
2873 //end if else file exists already
2875 if($add_logic == true){
2877 //reorder array by element[0]
2878 //$hook_array = reorder_array($hook_array, $event);
2879 //!!!Finish this above TODO
2881 $new_contents = replace_or_add_logic_type($hook_array);
2882 write_logic_file($module_name, $new_contents);
2884 //end if add_element is true
2887 //end function check_logic_hook_file
2890 function remove_logic_hook($module_name, $event, $action_array) {
2891 require_once('include/utils/logic_utils.php');
2894 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2895 // The file exists, let's make sure the hook is there
2896 $hook_array = get_hook_array($module_name);
2898 if(check_existing_element($hook_array, $event, $action_array)==true){
2899 // The hook is there, time to take it out.
2901 foreach ( $hook_array[$event] as $i => $hook ) {
2902 // We don't do a full comparison below just in case the filename changes
2903 if ( $hook[0] == $action_array[0]
2904 && $hook[1] == $action_array[1]
2905 && $hook[3] == $action_array[3]
2906 && $hook[4] == $action_array[4] ) {
2907 unset($hook_array[$event][$i]);
2911 $new_contents = replace_or_add_logic_type($hook_array);
2912 write_logic_file($module_name, $new_contents);
2918 function display_stack_trace($textOnly=false){
2920 $stack = debug_backtrace();
2922 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2930 foreach($stack as $item) {
2936 if(isset($item['file']))
2937 $file = $item['file'];
2938 if(isset($item['class']))
2939 $class = $item['class'];
2940 if(isset($item['line']))
2941 $line = $item['line'];
2942 if(isset($item['function']))
2943 $function = $item['function'];
2947 $out .= '<font color="black"><b>';
2953 $out .= '</b></font><font color="blue">';
2956 $out .= "[L:{$line}]";
2959 $out .= '</font><font color="red">';
2962 $out .= "({$class}:{$function})";
2965 $out .= '</font><br>';
2977 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2978 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2979 $halt_script = true;
2981 case 2048: return; //depricated we have lots of these ignore them
2984 if ( error_reporting() & E_NOTICE ) {
2985 $halt_script = false;
2991 case E_USER_WARNING:
2992 case E_COMPILE_WARNING:
2993 case E_CORE_WARNING:
2996 $halt_script = false;
3001 case E_COMPILE_ERROR:
3005 $type = "Fatal Error";
3010 $type = "Parse Error";
3014 //don't know what it is might not be so bad
3015 $halt_script = false;
3016 $type = "Unknown Error ($errno)";
3019 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3021 display_stack_trace();
3031 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3033 set_error_handler('StackTraceErrorHandler');
3035 function get_sub_cookies($name){
3037 if(isset($_COOKIE[$name])){
3038 $subs = explode('#', $_COOKIE[$name]);
3039 foreach($subs as $cookie){
3040 if(!empty($cookie)){
3041 $cookie = explode('=', $cookie);
3043 $cookies[$cookie[0]] = $cookie[1];
3052 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3054 if(!empty($sub_object_array)){
3056 foreach($sub_object_array as $sub_object){
3058 //run_second level is set to true if you need to remove sub-sub components
3059 if($run_second_level==true){
3061 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3063 //end if run_second_level is true
3065 $sub_object->mark_deleted($sub_object->id);
3066 //end foreach sub component
3068 //end if this is not empty
3071 //end function mark_delete_components
3075 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3077 function return_bytes($val)
3080 $last = strtolower($val{strlen($val)-1});
3084 // The 'G' modifier is available since PHP 5.1.0
3097 * Adds the href HTML tags around any URL in the $string
3099 function url2html($string) {
3101 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3102 return $return_string;
3104 // End customization by Julian
3107 * tries to determine whether the Host machine is a Windows machine
3109 function is_windows() {
3110 static $is_windows = null;
3111 if (!isset($is_windows)) {
3112 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3118 * equivalent for windows filesystem for PHP's is_writable()
3119 * @param string file Full path to the file/dir
3120 * @return bool true if writable
3122 function is_writable_windows($file) {
3123 if($file{strlen($file)-1}=='/') {
3124 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3127 // the assumption here is that Windows has an inherited permissions scheme
3128 // any file that is a descendant of an unwritable directory will inherit
3129 // that property and will trigger a failure below.
3134 $file = str_replace("/", '\\', $file);
3136 if(file_exists($file)) {
3137 if (!($f = @sugar_fopen($file, 'r+')))
3143 if(!($f = @sugar_fopen($file, 'w')))
3152 * best guesses Timezone based on webserver's TZ settings
3154 function lookupTimezone($userOffset = 0)
3156 return TimeDate::guessTimezone($userOffset);
3159 function convert_module_to_singular($module_array){
3162 foreach($module_array as $key => $value){
3163 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3165 if($value=="Cases") {
3166 $module_array[$key] = "Case";
3168 if($key=="projecttask"){
3169 $module_array['ProjectTask'] = "Project Task";
3170 unset($module_array[$key]);
3174 return $module_array;
3176 //end function convert_module_to_singular
3180 * Given the bean_name which may be plural or singular return the singular
3181 * bean_name. This is important when you need to include files.
3183 function get_singular_bean_name($bean_name){
3184 global $beanFiles, $beanList;
3185 if(array_key_exists($bean_name, $beanList)){
3186 return $beanList[$bean_name];
3194 * Given the potential module name (singular name, renamed module name)
3195 * Return the real internal module name.
3197 function get_module_from_singular($singular) {
3199 // find the internal module name for a singular name
3200 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3202 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3204 foreach ($singular_modules as $mod_name=>$sin_name) {
3205 if ($singular == $sin_name and $mod_name != $sin_name) {
3211 // find the internal module name for a renamed module
3212 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3214 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3216 foreach ($moduleList as $mod_name=>$name) {
3217 if ($singular == $name and $mod_name != $name) {
3223 // if it's not a singular name, nor a renamed name, return the original value
3227 function get_label($label_tag, $temp_module_strings){
3228 global $app_strings;
3229 if(!empty($temp_module_strings[$label_tag])){
3231 $label_name = $temp_module_strings[$label_tag];
3233 if(!empty($app_strings[$label_tag])){
3234 $label_name = $app_strings[$label_tag];
3236 $label_name = $label_tag;
3241 //end function get_label
3245 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3247 $rel_list = array();
3249 foreach($focus->relationship_fields as $rel_key => $rel_value){
3250 if($rel_value == $relationship_name){
3251 $temp_bean = get_module_info($tar_rel_module);
3252 // echo $focus->$rel_key;
3253 $temp_bean->retrieve($focus->$rel_key);
3254 if($temp_bean->id!=""){
3256 $rel_list[] = $temp_bean;
3262 foreach($focus->field_defs as $field_name => $field_def){
3263 //Check if the relationship_name matches a "relate" field
3264 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3265 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3266 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3267 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3269 $temp_bean = get_module_info($tar_rel_module);
3270 // echo $focus->$field_def['id_name'];
3271 $temp_bean->retrieve($focus->$field_def['id_name']);
3272 if($temp_bean->id!=""){
3274 $rel_list[] = $temp_bean;
3277 //Check if the relationship_name matches a "link" in a relate field
3278 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3279 $temp_bean = get_module_info($tar_rel_module);
3280 // echo $focus->$rel_value['id_name'];
3281 $temp_bean->retrieve($focus->$rel_value['id_name']);
3282 if($temp_bean->id!=""){
3284 $rel_list[] = $temp_bean;
3290 // special case for unlisted parent-type relationships
3291 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3292 $temp_bean = get_module_info($tar_rel_module);
3293 $temp_bean->retrieve($focus->parent_id);
3294 if($temp_bean->id!=""){
3295 $rel_list[] = $temp_bean;
3302 //end function search_filter_rel_info
3305 function get_module_info($module_name){
3309 //Get dictionary and focus data for module
3310 $vardef_name = $beanList[$module_name];
3312 if($vardef_name=="aCase"){
3313 $class_name = "Case";
3315 $class_name = $vardef_name;
3318 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3322 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3324 $module_bean = new $vardef_name();
3325 return $module_bean;
3326 //end function get_module_table
3330 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3332 * @param string $moduleName
3334 function get_valid_bean_name($module_name){
3337 $vardef_name = $beanList[$module_name];
3338 if($vardef_name=="aCase"){
3339 $bean_name = "Case";
3341 $bean_name = $vardef_name;
3348 function checkAuthUserStatus(){
3355 * This function returns an array of phpinfo() results that can be parsed and
3356 * used to figure out what version we run, what modules are compiled in, etc.
3357 * @param $level int info level constant (1,2,4,8...64);
3358 * @return $returnInfo array array of info about the PHP environment
3359 * @author original by "code at adspeed dot com" Fron php.net
3360 * @author customized for Sugar by Chris N.
3362 function getPhpInfo($level=-1) {
3363 /** Name (constant) Value Description
3364 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3365 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3366 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3367 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3368 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3369 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3370 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3371 INFO_ALL -1 Shows all of the above. This is the default value.
3375 $phpinfo = ob_get_contents();
3378 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3379 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3380 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3381 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3384 $returnInfo = array();
3386 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3387 $returnInfo['PHP Version'] = $version[1];
3391 for ($i=1; $i<count($parsedInfo); $i++) {
3392 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3393 $vName = trim($match[1]);
3394 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3396 foreach ($parsedInfo2 AS $vOne) {
3397 $vPat = '<info>([^<]+)<\/info>';
3398 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3399 $vPat2 = "/$vPat\s*$vPat/";
3401 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3402 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3403 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3404 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3416 * This function will take a string that has tokens like {0}, {1} and will replace
3417 * those tokens with the args provided
3418 * @param $format string to format
3419 * @param $args args to replace
3420 * @return $result a formatted string
3422 function string_format($format, $args){
3426 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3427 * IN () fails and IN ('') works.
3429 if (count($args) == 1)
3432 $singleArgument = current($args);
3433 if (empty($singleArgument))
3435 return str_replace("{0}", "''", $result);
3440 for($i = 0; $i < count($args); $i++){
3441 $result = str_replace('{'.$i.'}', $args[$i], $result);
3447 * Generate a string for displaying a unique identifier that is composed
3448 * of a system_id and number. This is use to allow us to generate quote
3449 * numbers using a DB auto-increment key from offline clients and still
3450 * have the number be unique (since it is modified by the system_id.
3452 * @param $num of bean
3453 * @param $system_id from system
3454 * @return $result a formatted string
3456 function format_number_display($num, $system_id){
3457 global $sugar_config;
3458 if(isset($num) && !empty($num)){
3459 $num=unformat_number($num);
3460 if(isset($system_id) && $system_id == 1){
3461 return sprintf("%d", $num);
3464 return sprintf("%d-%d", $num, $system_id);
3468 function checkLoginUserStatus(){
3472 * This function will take a number and system_id and format
3473 * @param $url URL containing host to append port
3474 * @param $port the port number - if '' is passed, no change to url
3475 * @return $resulturl the new URL with the port appended to the host
3477 function appendPortToHost($url, $port)
3481 // if no port, don't change the url
3484 $split = explode("/", $url);
3485 //check if it starts with http, in case they didn't include that in url
3486 if(str_begin($url, 'http'))
3488 //third index ($split[2]) will be the host
3489 $split[2] .= ":".$port;
3491 else // otherwise assumed to start with host name
3493 //first index ($split[0]) will be the host
3494 $split[0] .= ":".$port;
3497 $resulturl = implode("/", $split);
3504 * Singleton to return JSON object
3505 * @return JSON object
3507 function getJSONobj() {
3508 static $json = null;
3510 require_once('include/JSON.php');
3511 $json = new JSON(JSON_LOOSE_TYPE);
3516 require_once('include/utils/db_utils.php');
3519 * Set default php.ini settings for entry points
3521 function setPhpIniSettings() {
3523 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3525 if(function_exists('gzclose') && headers_sent() == false) {
3526 ini_set('zlib.output_compression', 1);
3530 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3532 /*if(function_exists('mb_strlen')) {
3533 ini_set('mbstring.func_overload', 7);
3534 ini_set('mbstring.internal_encoding', 'UTF-8');
3538 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3539 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3540 $backtrack_limit = ini_get('pcre.backtrack_limit');
3541 if(!empty($backtrack_limit)) {
3542 ini_set('pcre.backtrack_limit', '-1');
3547 * like array_merge() but will handle array elements that are themselves arrays;
3548 * PHP's version just overwrites the element with the new one.
3550 * @internal Note that this function deviates from the internal array_merge()
3551 * functions in that it does does not treat numeric keys differently
3552 * than string keys. Additionally, it deviates from
3553 * array_merge_recursive() by not creating an array when like values
3556 * @param array gimp the array whose values will be overloaded
3557 * @param array dom the array whose values will pwn the gimp's
3558 * @return array beaten gimp
3560 function sugarArrayMerge($gimp, $dom) {
3561 if(is_array($gimp) && is_array($dom)) {
3562 foreach($dom as $domKey => $domVal) {
3563 if(array_key_exists($domKey, $gimp)) {
3564 if(is_array($domVal)) {
3566 foreach ( $domVal as $domArrKey => $domArrVal )
3567 $tempArr[$domArrKey] = $domArrVal;
3568 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3569 if ( !array_key_exists($gimpArrKey, $tempArr) )
3570 $tempArr[$gimpArrKey] = $gimpArrVal;
3571 $gimp[$domKey] = $tempArr;
3573 $gimp[$domKey] = $domVal;
3576 $gimp[$domKey] = $domVal;
3580 // if the passed value for gimp isn't an array, then return the $dom
3581 elseif(is_array($dom))
3588 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3590 * @param array gimp the array whose values will be overloaded
3591 * @param array dom the array whose values will pwn the gimp's
3592 * @return array beaten gimp
3594 function sugarArrayMergeRecursive($gimp, $dom) {
3595 if(is_array($gimp) && is_array($dom)) {
3596 foreach($dom as $domKey => $domVal) {
3597 if(array_key_exists($domKey, $gimp)) {
3598 if(is_array($domVal) && is_array($gimp[$domKey])) {
3599 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3601 $gimp[$domKey] = $domVal;
3604 $gimp[$domKey] = $domVal;
3608 // if the passed value for gimp isn't an array, then return the $dom
3609 elseif(is_array($dom))
3616 * finds the correctly working versions of PHP-JSON
3617 * @return bool True if NOT found or WRONG version
3619 function returnPhpJsonStatus() {
3620 if(function_exists('json_encode')) {
3621 $phpInfo = getPhpInfo(8);
3622 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3624 return true; // not found
3629 * getTrackerSubstring
3631 * Returns a [number]-char or less string for the Tracker to display in the header
3632 * based on the tracker_max_display_length setting in config.php. If not set,
3633 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3635 * @param string name field for a given Object
3636 * @return string [number]-char formatted string if length of string exceeds the max allowed
3638 function getTrackerSubstring($name) {
3639 static $max_tracker_item_length;
3642 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3643 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3645 global $sugar_config;
3647 if(!isset($max_tracker_item_length)) {
3648 if(isset($sugar_config['tracker_max_display_length'])) {
3649 $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;
3651 $max_tracker_item_length = 15;
3655 if($strlen > $max_tracker_item_length) {
3656 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length);
3663 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3664 $where_clauses= array();
3666 $table_name=$bean->object_name;
3667 foreach ($field_list[$module] as $field=>$parms) {
3668 if(isset($values[$field]) && $values[$field] != "") {
3670 if (!empty($parms['operator'])) {
3671 $operator=$parms['operator'];
3673 if (is_array($values[$field])) {
3676 foreach ($values[$field] as $key => $val) {
3677 if ($val != ' ' and $val != '') {
3678 if (!empty($field_value)) {
3681 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3685 $field_value=$GLOBALS['db']->quote($values[$field]);
3687 //set db_fields array.
3688 if (!isset($parms['db_field']) ) {
3689 $parms['db_field'] = array($field);
3691 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3692 global $current_user;
3693 $field_value = $GLOBALS['db']->quote($current_user->id);
3699 if ($field_value != '') {
3701 foreach ($parms['db_field'] as $db_field) {
3702 if (strstr($db_field,'.')===false) {
3703 $db_field=$bean->table_name.".".$db_field;
3705 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3706 $db_field='upper('.$db_field.")";
3707 $field_value=strtoupper($field_value);
3711 if (!empty($where)) {
3714 switch (strtolower($operator)) {
3716 $where .= $db_field . " like '".$field_value.$like_char."'";
3719 $where .= $db_field . " in (".$field_value.')';
3722 $where .= $db_field . " = '".$field_value ."'";
3727 if (!empty($where)) {
3729 array_push($where_clauses, '( '.$where.' )');
3731 array_push($where_clauses, $where);
3736 if ($add_custom_fields) {
3737 require_once('modules/DynamicFields/DynamicField.php');
3738 $bean->setupCustomFields($module);
3739 $bean->custom_fields->setWhereClauses($where_clauses);
3741 return $where_clauses;
3744 function add_quotes($str) {
3749 * This function will rebuild the config file
3750 * @param $sugar_config
3751 * @param $sugar_version
3752 * @return bool true if successful
3754 function rebuildConfigFile($sugar_config, $sugar_version) {
3755 // add defaults to missing values of in-memory sugar_config
3756 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3757 // need to override version with default no matter what
3758 $sugar_config['sugar_version'] = $sugar_version;
3760 ksort( $sugar_config );
3762 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3771 * getJavascriptSiteURL
3772 * This function returns a URL for the client javascript calls to access
3773 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3774 * are used to access the site. Thus, the hostname in the URL returned may
3775 * not always match that of $sugar_config['site_url']. Basically, the
3776 * assumption is that however the user accessed the website is how they
3777 * will continue to with subsequent javascript requests. If the variable
3778 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3779 * @return $site_url The url used to refer to the website
3781 function getJavascriptSiteURL() {
3782 global $sugar_config;
3783 if(!empty($_SERVER['HTTP_REFERER'])) {
3784 $url = parse_url($_SERVER['HTTP_REFERER']);
3785 $replacement_url = $url['scheme']."://".$url['host'];
3786 if(!empty($url['port']))
3787 $replacement_url .= ':'.$url['port'];
3788 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3790 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3791 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3792 $site_url = preg_replace('/^http\:/','https:',$site_url);
3795 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3799 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3800 function add_squotes($str) {
3801 return "'" . $str . "'";
3805 // recursive function to count the number of levels within an array
3806 function array_depth($array, $depth_count=-1, $depth_array=array()){
3808 if (is_array($array)){
3809 foreach ($array as $key => $value){
3810 $depth_array[] = array_depth($value, $depth_count);
3814 return $depth_count;
3816 foreach ($depth_array as $value){
3817 $depth_count = $value > $depth_count ? $value : $depth_count;
3819 return $depth_count;
3823 * Creates a new Group User
3824 * @param string $name Name of Group User
3825 * @return string GUID of new Group User
3827 function createGroupUser($name) {
3830 $group = new User();
3831 $group->user_name = $name;
3832 $group->last_name = $name;
3833 $group->is_group = 1;
3834 $group->deleted = 0;
3835 $group->status = 'Active'; // cn: bug 6711
3836 $group->setPreference('timezone', TimeDate::userTimezone());
3843 * Helper function to locate an icon file given only a name
3844 * Searches through the various paths for the file
3845 * @param string iconFileName The filename of the icon
3846 * @return string Relative pathname of the located icon, or '' if not found
3849 function _getIcon($iconFileName)
3852 $iconName = "icon_{$iconFileName}.gif";
3853 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3855 //First try un-ucfirst-ing the icon name
3856 if ( empty($iconFound) )
3857 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3858 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3860 //Next try removing the icon prefix
3861 if ( empty($iconFound) )
3862 $iconName = "{$iconFileName}.gif";
3863 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3865 if ( empty($iconFound) )
3871 * Function to grab the correct icon image for Studio
3872 * @param string $iconFileName Name of the icon file
3873 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3874 * @param string $width Width of image
3875 * @param string $height Height of image
3876 * @param string $align Alignment of image
3877 * @param string $alt Alt tag of image
3878 * @return string $string <img> tag with corresponding image
3881 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
3883 global $app_strings, $theme;
3885 $iconName = _getIcon($iconFileName);
3886 if(empty($iconName)){
3887 $iconName = _getIcon($altFileName);
3888 if (empty($iconName))
3890 return $app_strings['LBL_NO_IMAGE'];
3893 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3897 * Function to grab the correct icon image for Dashlets Dialog
3898 * @param string $filename Location of the icon file
3899 * @param string $module Name of the module to fall back onto if file does not exist
3900 * @param string $width Width of image
3901 * @param string $height Height of image
3902 * @param string $align Alignment of image
3903 * @param string $alt Alt tag of image
3904 * @return string $string <img> tag with corresponding image
3907 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
3908 global $app_strings, $theme;
3909 $iconName = _getIcon($module . "_32");
3910 if (empty($iconName))
3912 $iconName = _getIcon($module);
3914 if(empty($iconName)){
3915 return $app_strings['LBL_NO_IMAGE'];
3917 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3920 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3921 function html_entity_decode_utf8($string)
3924 // replace numeric entities
3925 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3926 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3927 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
3928 // replace literal entities
3929 if (!isset($trans_tbl))
3931 $trans_tbl = array();
3932 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3933 $trans_tbl[$key] = utf8_encode($val);
3935 return strtr($string, $trans_tbl);
3938 // Returns the utf string corresponding to the unicode value
3939 function code2utf($num)
3941 if ($num < 128) return chr($num);
3942 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3943 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3944 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3948 function str_split_php4($string, $length = 1) {
3949 $string_length = strlen($string);
3952 if ($length > $string_length) {
3953 // use the string_length as the string is shorter than the length
3954 $length = $string_length;
3956 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3957 $return[] = substr($string, $cursor, $length);
3962 if (version_compare(phpversion(), '5.0.0', '<')) {
3963 function str_split($string, $length = 1) {
3964 return str_split_php4($string, $length);
3969 * @deprecated use DBManagerFactory::isFreeTDS
3971 function is_freetds()
3973 return DBManagerFactory::isFreeTDS();
3977 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3979 * @todo this won't work completely right until we impliment css compression and combination
3980 * for now, we'll just include the last css file found.
3982 * @return chart.css file to use
3984 function chartStyle()
3986 return SugarThemeRegistry::current()->getCSSURL('chart.css');
3990 * Chart dashlet helper functions that returns the correct XML color file for charts,
3991 * dependent on the current theme.
3993 * @return sugarColors.xml to use
3995 function chartColors()
3997 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
3998 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
3999 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4001 /* End Chart Dashlet helper functions */
4004 * This function is designed to set up the php enviroment
4005 * for AJAX requests.
4008 function ajaxInit() {
4009 ini_set('display_errors', 'false');
4013 * Returns an absolute path from the given path, determining if it is relative or absolute
4015 * @param string $path
4018 function getAbsolutePath(
4020 $currentServer = false
4023 $path = trim($path);
4025 // try to match absolute paths like \\server\share, /directory or c:\
4026 if ( ( substr($path,0,2) == '\\\\' )
4027 || ( $path[0] == '/' )
4028 || preg_match('/^[A-z]:/i',$path)
4032 return getcwd().'/'.$path;
4036 * Returns the bean object of the given module
4038 * @deprecated use SugarModule::loadBean() instead
4039 * @param string $module
4046 return SugarModule::get($module)->loadBean();
4051 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4053 function isTouchScreen()
4055 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4057 // first check if we have forced use of the touch enhanced interface
4058 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4062 // next check if we should use the touch interface with our device
4063 if ( strpos($ua, 'ipad') !== false ) {
4071 * Returns the shortcut keys to access the shortcut links. Shortcut
4072 * keys vary depending on browser versions and operating systems.
4073 * @return String value of the shortcut keys
4075 function get_alt_hot_key() {
4077 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4078 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4079 $isMac = strpos($ua, 'mac') !== false;
4080 $isLinux = strpos($ua, 'linux') !== false;
4082 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4083 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4084 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4087 return $isMac ? 'Ctrl+' : 'Alt+';
4090 function can_start_session(){
4091 if(!empty($_GET['PHPSESSID'])) {
4094 $session_id = session_id();
4095 return empty($session_id) ? true : false;
4098 function load_link_class($properties){
4100 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4101 require_once($properties['link_file']);
4102 $class = $properties['link_class'];
4108 function inDeveloperMode()
4110 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4114 * Filter the protocol list for inbound email accounts.
4116 * @param array $protocol
4118 function filterInboundEmailPopSelection($protocol)
4120 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4122 if( isset($protocol['pop3']) )
4123 unset($protocol['pop3']);
4126 $protocol['pop3'] = 'POP3';
4132 * The function is used because currently we are not supporting mbstring.func_overload
4133 * 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.
4134 * 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.
4135 * @returns the substred strings.
4137 function sugar_substr($string, $length, $charset='UTF-8')
4139 if(mb_strlen($string,$charset) > $length) {
4140 $string = trim(mb_substr(trim($string),0,$length,$charset));
4146 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4147 * This will work even without setting the mbstring.*encoding
4149 function sugar_ucfirst($string, $charset='UTF-8') {
4150 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4157 function unencodeMultienum($string) {
4158 if (is_array($string))
4162 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4163 $string = substr(substr($string, 1), 0, strlen($string) -2);
4166 return explode('^,^', $string);
4169 function encodeMultienumValue($arr) {
4170 if (!is_array($arr))
4176 $string = "^" . implode('^,^', $arr) . "^";
4182 * create_export_query is used for export and massupdate
4183 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4184 * This function will correct the where clause and output necessary join condition for them
4185 * @param $module: the module name
4186 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4187 * @param $where: where clauses
4188 * @return $ret_array['where']: corrected where clause
4189 * @return $ret_array['join']: extra join condition
4191 function create_export_query_relate_link_patch($module, $searchFields, $where){
4192 if(file_exists('modules/'.$module.'/SearchForm.html')){
4193 $ret_array['where'] = $where;
4196 $seed = loadBean($module);
4197 foreach($seed->field_defs as $name=>$field)
4200 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4201 $seed->load_relationship($field['link']);
4203 if(empty($join_type))
4205 $params['join_type'] = ' LEFT JOIN ';
4209 $params['join_type'] = $join_type;
4211 if(isset($data['join_name']))
4213 $params['join_table_alias'] = $field['join_name'];
4217 $params['join_table_alias'] = 'join_'.$field['name'];
4220 if(isset($data['join_link_name']))
4222 $params['join_table_link_alias'] = $field['join_link_name'];
4226 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4228 $join = $seed->$field['link']->getJoin($params, true);
4229 $join_table_alias = 'join_'.$field['name'];
4230 if(isset($field['db_concat_fields'])){
4231 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4232 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4234 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4238 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4243 * 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.
4244 * @Depends on QuickRepairAndRebuild.php
4245 * @Relate bug 30642 ,23177
4247 function clearAllJsAndJsLangFilesWithoutOutput(){
4248 global $current_language , $mod_strings;
4249 $MBmodStrings = $mod_strings;
4250 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4251 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4252 $repair = new RepairAndClear();
4253 $repair->module_list = array();
4254 $repair->show_output = false;
4255 $repair->clearJsLangFiles();
4256 $repair->clearJsFiles();
4257 $mod_strings = $MBmodStrings;
4261 * This function will allow you to get a variable value from query string
4263 function getVariableFromQueryString($variable, $string){
4265 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4275 * should_hide_iframes
4276 * This is a helper method to determine whether or not to show iframes (My Sites) related
4277 * information in the application.
4279 * @return boolean flag indicating whether or not iframes module should be hidden
4281 function should_hide_iframes() {
4282 //Remove the MySites module
4283 if(file_exists('modules/iFrames/iFrame.php')) {
4284 if(!class_exists("iFrame")) {
4285 require_once('modules/iFrames/iFrame.php');
4293 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4295 * @param string $version
4296 * @return string RC, BETA, GA
4298 function getVersionStatus($version){
4299 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4300 return strtoupper($matches[1]);
4307 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4308 * 5.5.1RC1 then return 5.5.1
4310 * @param string $version
4313 function getMajorMinorVersion($version){
4314 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4315 $version = $matches2[1];
4316 $arr = explode('.', $version);
4317 if(count($arr) > 2){
4319 $version = substr($version, 0, 3);
4327 * Return string composed of seconds & microseconds of current time, without dots
4330 function sugar_microtime()
4332 $now = explode(' ', microtime());
4333 $unique_id = $now[1].str_replace('.', '', $now[0]);
4338 * Extract urls from a piece of text
4340 * @return array of urls found in $string
4342 function getUrls($string)
4344 $lines = explode("<br>", trim($string));
4346 foreach($lines as $line){
4347 $regex = '/http?\:\/\/[^\" ]+/i';
4348 preg_match_all($regex, $line, $matches);
4349 foreach($matches[0] as $match){
4358 * Sanitize image file from hostile content
4359 * @param string $path Image file
4360 * @param bool $jpeg Accept only JPEGs?
4362 function verify_image_file($path, $jpeg = false)
4364 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4365 $img = imagecreatefromstring(file_get_contents($path));
4369 $img_size = getimagesize($path);
4370 $filetype = $img_size['mime'];
4371 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4372 if($filetype == "image/jpeg" || $jpeg) {
4375 $image = ob_get_clean();
4376 // not writing directly because imagejpeg does not work with streams
4377 if(file_put_contents($path, $image)) {
4380 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4381 imagealphablending($img, true);
4382 imagesavealpha($img, true);
4385 $image = ob_get_clean();
4386 if(file_put_contents($path, $image)) {
4393 // check image manually
4394 $fp = fopen($path, "r");
4395 if(!$fp) return false;
4396 $data = fread($fp, 4096);
4398 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",
4400 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4409 * Verify uploaded image
4410 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4411 * @param string $path Image path
4412 * @param bool $jpeg_only Accept only JPEGs?
4414 function verify_uploaded_image($path, $jpeg_only = false)
4416 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4418 $supportedExtensions['png'] = 'image/png';
4421 if(!file_exists($path) || !is_file($path)) {
4425 $img_size = getimagesize($path);
4426 $filetype = $img_size['mime'];
4427 $ext = end(explode(".", $path));
4428 if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4429 !in_array($filetype, array_values($supportedExtensions))) {
4432 return verify_image_file($path, $jpeg_only);
4435 function cmp_beans($a, $b)
4437 global $sugar_web_service_order_by;
4438 //If the order_by field is not valid, return 0;
4439 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4442 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4443 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4447 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4455 function order_beans($beans, $field_name)
4457 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4458 global $sugar_web_service_order_by;
4459 $sugar_web_service_order_by = $field_name;
4460 usort($beans, "cmp_beans");
4465 * Return search like string
4466 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4467 * @param string $str string to be searched
4468 * @param string $like_char Database like character, usually '%'
4469 * @return string Returns a string to be searched in db query
4471 function sql_like_string($str, $like_char) {
4473 // default behaviour
4476 // override default wildcard character
4477 if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4478 strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4479 $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4482 // add wildcard at the beginning of the search string
4483 if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4484 $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4485 if (substr($str,0,1) <> $wildcard)
4486 $str = $wildcard.$str;
4489 // add wildcard at the end of search string (default)
4490 if(substr($str,-1) <> $wildcard) {
4494 return str_replace($wildcard, $like_char, $str);
4497 //check to see if custom utils exists
4498 if(file_exists('custom/include/custom_utils.php')){
4499 include_once('custom/include/custom_utils.php');
4502 //check to see if custom utils exists in Extension framework
4503 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4504 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4507 * @param $input - the input string to sanitize
4508 * @param int $quotes - use quotes
4509 * @param string $charset - the default charset
4510 * @param bool $remove - strip tags or not
4511 * @return string - the sanitized string
4513 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4515 return htmlentities($input, $quotes, $charset);
4520 * utf8_recursive_encode
4522 * This function walks through an Array and recursively calls utf8_encode on the
4523 * values of each of the elements.
4525 * @param $data Array of data to encode
4526 * @return utf8 encoded Array data
4528 function utf8_recursive_encode($data)
4531 foreach($data as $key=>$val) {
4532 if(is_array($val)) {
4533 $result[$key] = utf8_recursive_encode($val);
4535 $result[$key] = utf8_encode($val);
4542 * get_language_header
4544 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4545 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4547 * @return String The lang=[Current Language] markup to insert into the <html> tag
4549 function get_language_header()
4551 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4556 * get_custom_file_if_exists
4558 * This function handles the repetitive code we have where we first check if a file exists in the
4559 * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
4560 * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
4561 * otherwise it return $file
4563 * @param $file String of filename to check
4564 * @return $file String of filename including custom directory if found
4566 function get_custom_file_if_exists($file)
4568 return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4575 * This will return the URL used to redirect the user to the help documentation.
4576 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4577 * in config.php or config_override.php.
4579 * @param string $send_edition
4580 * @param string $send_version
4581 * @param string $send_lang
4582 * @param string $send_module
4583 * @param string $send_action
4584 * @param string $dev_status
4585 * @param string $send_key
4586 * @param string $send_anchor
4587 * @return string the completed help URL
4589 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4590 global $sugar_config;
4592 if (!empty($sugar_config['custom_help_url'])) {
4593 $sendUrl = $sugar_config['custom_help_url'];
4595 if (!empty($sugar_config['custom_help_base_url'])) {
4596 $baseUrl= $sugar_config['custom_help_base_url'];
4598 $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4600 $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4601 if(!empty($send_anchor)) {
4602 $sendUrl .= "&anchor=".$send_anchor;