2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2011 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'),
218 function get_sugar_config_defaults() {
221 * used for getting base values for array style config.php. used by the
222 * installer and to fill in new entries on upgrades. see also:
226 $sugar_config_defaults = array (
227 'admin_export_only' => false,
228 'export_delimiter' => ',',
229 'cache_dir' => 'cache/',
230 'calculate_response_time' => true,
231 'create_default_user' => false,
232 'chartEngine' => 'Jit',
233 'date_formats' => array (
234 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
235 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
236 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
237 'name_formats' => array (
238 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
239 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
241 'dbconfigoption' => array (
242 'persistent' => true,
246 'default_action' => 'index',
247 'default_charset' => return_session_value_or_default('default_charset',
249 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
250 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
251 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
252 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
253 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
254 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
255 'default_date_format' => 'm/d/Y',
256 'default_locale_name_format' => 's f l',
257 'default_export_charset' => 'UTF-8',
258 'default_language' => return_session_value_or_default('default_language',
260 'default_module' => 'Home',
261 'default_password' => '',
262 'default_permissions' => array (
268 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
269 'default_time_format' => 'h:ia',
270 'default_user_is_admin' => false,
271 'default_user_name' => '',
272 'disable_export' => false,
273 'disable_persistent_connections' =>
274 return_session_value_or_default('disable_persistent_connections',
276 'display_email_template_variable_chooser' => false,
277 'display_inbound_email_buttons' => false,
278 'dump_slow_queries' => false,
279 'email_default_editor' => 'html',
280 'email_default_client' => 'sugar',
281 'email_default_delete_attachments' => true,
282 'history_max_viewed' => 50,
283 'installer_locked' => true,
284 'import_max_records_per_file' => 100,
285 'import_max_records_total_limit' => '',
286 'languages' => array('en_us' => 'English (US)'),
287 'large_scale_test' => false,
288 'list_max_entries_per_page' => 20,
289 'list_max_entries_per_subpanel' => 10,
290 'lock_default_user_name' => false,
291 'log_memory_usage' => false,
292 'portal_view' => 'single_user',
293 'resource_management' => array (
294 'special_query_limit' => 50000,
295 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
296 'default_limit' => 1000,
298 'require_accounts' => true,
299 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
301 'save_query' => 'all',
302 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
303 'showThemePicker' => true,
304 'slow_query_time_msec' => '100',
306 'time_formats' => array (
307 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
308 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
309 'tracker_max_display_length' => 15,
310 'translation_string_prefix' =>
311 return_session_value_or_default('translation_string_prefix', false),
312 'upload_badext' => array (
313 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
314 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
315 'upload_maxsize' => 30000000,
316 'import_max_execution_time' => 3600,
317 // 'use_php_code_json' => returnPhpJsonStatus(),
318 'verify_client_ip' => true,
319 'js_custom_version' => '',
320 'js_lang_version' => 1,
321 'lead_conv_activity_opt' => 'donothing',
322 'default_number_grouping_seperator' => ',',
323 'default_decimal_seperator' => '.',
324 'lock_homepage' => false,
325 'lock_subpanels' => false,
326 'max_dashlets_homepage' => '15',
327 'default_max_tabs' => '7',
328 'dashlet_display_row_options' => array('1','3','5','10'),
329 'default_subpanel_tabs' => true,
330 'default_subpanel_links' => false,
331 'default_swap_last_viewed' => false,
332 'default_swap_shortcuts' => false,
333 'default_navigation_paradigm' => 'gm',
334 'admin_access_control' => false,
335 'use_common_ml_dir' => false,
336 'common_ml_dir' => '',
339 'default_view' => 'week',
340 'show_calls_by_default' => true,
341 'show_tasks_by_default' => true,
342 'editview_width' => 990,
343 'editview_height' => 480,
344 'day_timestep' => 15,
345 'week_timestep' => 30,
346 'month_timestep' => 60,
347 'items_draggable' => true,
348 'mouseover_expand' => true,
350 'passwordsetting' => empty($passwordsetting) ? array (
351 'SystemGeneratedPasswordON' => '',
352 'generatepasswordtmpl' => '',
353 'lostpasswordtmpl' => '',
354 'forgotpasswordON' => false,
355 'linkexpiration' => '1',
356 'linkexpirationtime' => '30',
357 'linkexpirationtype' => '1',
358 'systexpiration' => '0',
359 'systexpirationtime' => '',
360 'systexpirationtype' => '0',
361 'systexpirationlogin' => '',
362 ) : $passwordsetting,
363 'use_real_names' => true,
366 if(!is_object($locale)) {
367 $locale = new Localization();
370 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
372 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
373 return( $sugar_config_defaults );
377 * @deprecated use SugarView::getMenu() instead
379 function load_menu($path){
382 if(file_exists($path . 'Menu.php'))
384 require($path . 'Menu.php');
386 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
388 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
390 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
392 require('custom/application/Ext/Menus/menu.ext.php');
398 * get_notify_template_file
399 * This function will return the location of the email notifications template to use
401 * @return string relative file path to email notifications template file
403 function get_notify_template_file($language){
405 * Order of operation:
406 * 1) custom version of specified language
407 * 2) stock version of specified language
408 * 3) custom version of en_us template
409 * 4) stock en_us template
412 // set $file to the base code template so it's set if none of the conditions pass
413 $file = "include/language/en_us.notify_template.html";
415 if(file_exists("custom/include/language/{$language}.notify_template.html")){
416 $file = "custom/include/language/{$language}.notify_template.html";
418 else if(file_exists("include/language/{$language}.notify_template.html")){
419 $file = "include/language/{$language}.notify_template.html";
421 else if(file_exists("custom/include/language/en_us.notify_template.html")){
422 $file = "custom/include/language/en_us.notify_template.html";
428 function sugar_config_union( $default, $override ){
429 // a little different then array_merge and array_merge_recursive. we want
430 // the second array to override the first array if the same value exists,
431 // otherwise merge the unique keys. it handles arrays of arrays recursively
432 // might be suitable for a generic array_union
433 if( !is_array( $override ) ){
436 foreach( $default as $key => $value ){
437 if( !array_key_exists($key, $override) ){
438 $override[$key] = $value;
440 else if( is_array( $key ) ){
441 $override[$key] = sugar_config_union( $value, $override[$key] );
447 function make_not_writable( $file ){
448 // Returns true if the given file/dir has been made not writable
450 if( is_file($file) || is_dir($file) ){
451 if( !is_writable($file) ){
455 $original_fileperms = fileperms($file);
457 // take away writable permissions
458 $new_fileperms = $original_fileperms & ~0x0092;
459 @sugar_chmod($file, $new_fileperms);
461 if( !is_writable($file) ){
470 /** This function returns the name of the person.
471 * It currently returns "first last". It should not put the space if either name is not available.
472 * It should not return errors if either name is not available.
473 * If no names are present, it will return ""
474 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
475 * All Rights Reserved.
476 * Contributor(s): ______________________________________..
478 function return_name($row, $first_column, $last_column)
484 if(isset($row[$first_column]))
486 $first_name = stripslashes($row[$first_column]);
489 if(isset($row[$last_column]))
491 $last_name = stripslashes($row[$last_column]);
494 $full_name = $first_name;
496 // If we have a first name and we have a last name
497 if($full_name != "" && $last_name != "")
499 // append a space, then the last name
500 $full_name .= " ".$last_name;
502 // If we have no first name, but we have a last name
503 else if($last_name != "")
505 // append the last name without the space.
506 $full_name .= $last_name;
513 function get_languages()
515 global $sugar_config;
516 $lang = $sugar_config['languages'];
517 if(!empty($sugar_config['disabled_languages'])){
518 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
519 unset($lang[$disable]);
525 function get_all_languages()
527 global $sugar_config;
528 return $sugar_config['languages'];
532 function get_language_display($key)
534 global $sugar_config;
535 return $sugar_config['languages'][$key];
538 function get_assigned_user_name($assigned_user_id, $is_group = '') {
539 static $saved_user_list = null;
541 if(empty($saved_user_list)) {
542 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
545 if(isset($saved_user_list[$assigned_user_id])) {
546 return $saved_user_list[$assigned_user_id];
553 * retrieves the user_name column value (login)
554 * @param string id GUID of user
557 function get_user_name($id) {
561 $db = DBManagerFactory::getInstance();
563 $q = "SELECT user_name FROM users WHERE id='{$id}'";
565 $a = $db->fetchByAssoc($r);
567 return (empty($a)) ? '' : $a['user_name'];
571 //TODO Update to use global cache
572 function get_user_array($add_blank=true, $status="Active", $assigned_user="", $use_real_name=false, $user_name_begins = null, $is_group=' AND portal_only=0 ', $from_cache = true) {
574 global $sugar_config;
578 $locale = new Localization();
581 $user_array = get_register_value('user_array', $add_blank. $status . $assigned_user);
583 if(empty($user_array)) {
584 $db = DBManagerFactory::getInstance();
585 $temp_result = Array();
586 // Including deleted users for now.
587 if (empty($status)) {
588 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$is_group;
591 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$is_group;
594 if (!empty($user_name_begins)) {
595 $query .= " AND user_name LIKE '$user_name_begins%' ";
597 if (!empty($assigned_user)) {
598 $query .= " OR id='$assigned_user'";
600 $query = $query.' ORDER BY user_name ASC';
601 $GLOBALS['log']->debug("get_user_array query: $query");
602 $result = $db->query($query, true, "Error filling in user array: ");
604 if ($add_blank==true) {
605 // Add in a blank row
606 $temp_result[''] = '';
609 // Get the id and the name.
610 while($row = $db->fetchByAssoc($result)) {
611 if($use_real_name == true || showFullName()) {
612 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
613 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
615 $temp_result[$row['id']] = $row['user_name'];
618 $temp_result[$row['id']] = $row['user_name'];
622 $user_array = $temp_result;
624 set_register_value('user_array', $add_blank. $status . $assigned_user, $temp_result);
633 * uses a different query to return a list of users than get_user_array()
634 * @param args string where clause entry
635 * @return array Array of Users' details that match passed criteria
637 function getUserArrayFromFullName($args, $hide_portal_users = false) {
639 $db = DBManagerFactory::getInstance();
642 if(strpos($args, " ")) {
643 $argArray = explode(" ", $args);
649 foreach($argArray as $arg) {
650 if(!empty($inClause)) {
656 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
659 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
660 if ( $hide_portal_users ) {
661 $query .= " portal_only=0 AND ";
664 $query .= " ORDER BY last_name ASC";
666 $r = $db->query($query);
668 while($a = $db->fetchByAssoc($r)) {
669 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
677 * based on user pref then system pref
679 function showFullName() {
680 global $sugar_config;
681 global $current_user;
682 static $showFullName = null;
684 if (is_null($showFullName)) {
685 $sysPref = !empty($sugar_config['use_real_names']);
686 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
688 if($userPref != null) {
689 $showFullName = ($userPref == 'on');
691 $showFullName = $sysPref;
695 return $showFullName;
698 function clean($string, $maxLength)
700 $string = substr($string, 0, $maxLength);
701 return escapeshellcmd($string);
705 * Copy the specified request variable to the member variable of the specified object.
706 * Do no copy if the member variable is already set.
707 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
708 * All Rights Reserved.
709 * Contributor(s): ______________________________________..
711 function safe_map($request_var, & $focus, $always_copy = false)
713 safe_map_named($request_var, $focus, $request_var, $always_copy);
717 * Copy the specified request variable to the member variable of the specified object.
718 * Do no copy if the member variable is already set.
719 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
720 * All Rights Reserved.
721 * Contributor(s): ______________________________________..
723 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
725 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
726 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
727 $focus->$member_var = $_REQUEST[$request_var];
732 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
734 * @param string $language specific language to load
735 * @return array lang strings
737 function return_app_list_strings_language($language)
739 global $app_list_strings;
740 global $sugar_config;
742 $cache_key = 'app_list_strings.'.$language;
744 // Check for cached value
745 $cache_entry = sugar_cache_retrieve($cache_key);
746 if(!empty($cache_entry))
751 $default_language = $sugar_config['default_language'];
752 $temp_app_list_strings = $app_list_strings;
755 if ($language != 'en_us') {
758 if ($default_language != 'en_us' && $language != $default_language) {
759 $langs[] = $default_language;
761 $langs[] = $language;
763 $app_list_strings_array = array();
765 foreach ( $langs as $lang ) {
766 $app_list_strings = array();
767 if(file_exists("include/language/$lang.lang.php")) {
768 include("include/language/$lang.lang.php");
769 $GLOBALS['log']->info("Found language file: $lang.lang.php");
771 if(file_exists("include/language/$lang.lang.override.php")) {
772 include("include/language/$lang.lang.override.php");
773 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
775 if(file_exists("include/language/$lang.lang.php.override")) {
776 include("include/language/$lang.lang.php.override");
777 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
780 $app_list_strings_array[] = $app_list_strings;
783 $app_list_strings = array();
784 foreach ( $app_list_strings_array as $app_list_strings_item ) {
785 $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
788 foreach ( $langs as $lang ) {
789 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
790 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
791 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
793 if(file_exists("custom/include/language/$lang.lang.php")) {
794 include("custom/include/language/$lang.lang.php");
795 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
799 if(!isset($app_list_strings)) {
800 $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");
804 $return_value = $app_list_strings;
805 $app_list_strings = $temp_app_list_strings;
807 sugar_cache_put($cache_key, $return_value);
809 return $return_value;
813 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
814 * $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.
815 * @param file string the language that you want include,
816 * @param app_list_strings array the golbal strings
820 function _mergeCustomAppListStrings($file , $app_list_strings){
821 $app_list_strings_original = $app_list_strings;
822 unset($app_list_strings);
823 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
824 // This way, language file can add items to save specific standard codelist from being overwritten
825 $exemptDropdowns = array();
827 if(!isset($app_list_strings) || !is_array($app_list_strings)){
828 return $app_list_strings_original;
830 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
832 // FG - bug 45525 - Specific codelists must NOT be overwritten
833 $exemptDropdowns[] = "moduleList";
834 $exemptDropdowns[] = "parent_type_display";
835 $exemptDropdowns[] = "record_type_display";
836 $exemptDropdowns[] = "record_type_display_notes";
838 foreach($app_list_strings as $key=>$value)
840 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
842 unset($app_list_strings_original["$key"]);
845 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
846 return $app_list_strings;
850 * This function retrieves an application language file and returns the array of strings included.
852 * @param string $language specific language to load
853 * @return array lang strings
855 function return_application_language($language)
857 global $app_strings, $sugar_config;
859 $cache_key = 'app_strings.'.$language;
861 // Check for cached value
862 $cache_entry = sugar_cache_retrieve($cache_key);
863 if(!empty($cache_entry))
868 $temp_app_strings = $app_strings;
869 $default_language = $sugar_config['default_language'];
872 if ($language != 'en_us') {
875 if ($default_language != 'en_us' && $language != $default_language) {
876 $langs[] = $default_language;
879 $langs[] = $language;
881 $app_strings_array = array();
883 foreach ( $langs as $lang ) {
884 $app_strings = array();
885 if(file_exists("include/language/$lang.lang.php")) {
886 include("include/language/$lang.lang.php");
887 $GLOBALS['log']->info("Found language file: $lang.lang.php");
889 if(file_exists("include/language/$lang.lang.override.php")) {
890 include("include/language/$lang.lang.override.php");
891 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
893 if(file_exists("include/language/$lang.lang.php.override")) {
894 include("include/language/$lang.lang.php.override");
895 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
897 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
898 include("custom/application/Ext/Language/$lang.lang.ext.php");
899 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
901 if(file_exists("custom/include/language/$lang.lang.php")) {
902 include("custom/include/language/$lang.lang.php");
903 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
905 $app_strings_array[] = $app_strings;
908 $app_strings = array();
909 foreach ( $app_strings_array as $app_strings_item ) {
910 $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
913 if(!isset($app_strings)) {
914 $GLOBALS['log']->fatal("Unable to load the application language strings");
918 // If we are in debug mode for translating, turn on the prefix now!
919 if($sugar_config['translation_string_prefix']) {
920 foreach($app_strings as $entry_key=>$entry_value) {
921 $app_strings[$entry_key] = $language.' '.$entry_value;
924 if(isset($_SESSION['show_deleted'])) {
925 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
926 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
927 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
928 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
931 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
933 $return_value = $app_strings;
934 $app_strings = $temp_app_strings;
936 sugar_cache_put($cache_key, $return_value);
938 return $return_value;
942 * This function retrieves a module's language file and returns the array of strings included.
944 * @param string $language specific language to load
945 * @param string $module module name to load strings for
946 * @param bool $refresh optional, true if you want to rebuild the language strings
947 * @return array lang strings
949 function return_module_language($language, $module, $refresh=false)
952 global $sugar_config;
953 global $currentModule;
955 // Jenny - Bug 8119: Need to check if $module is not empty
956 if (empty($module)) {
957 $stack = debug_backtrace();
958 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
964 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
965 // Check for cached value
966 $cache_entry = sugar_cache_retrieve($cache_key);
967 if(!empty($cache_entry))
972 // Store the current mod strings for later
973 $temp_mod_strings = $mod_strings;
974 $loaded_mod_strings = array();
975 $language_used = $language;
976 $default_language = $sugar_config['default_language'];
978 if(empty($language)) {
979 $language = $default_language;
982 // Bug 21559 - So we can get all the strings defined in the template, refresh
983 // the vardefs file if the cached language file doesn't exist.
984 if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
985 && !empty($GLOBALS['beanList'][$module])){
986 $object = BeanFactory::getObjectName($module);
987 VardefManager::refreshVardefs($module,$object);
990 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
992 // cn: bug 6048 - merge en_us with requested language
993 if($language != $sugar_config['default_language'])
994 $loaded_mod_strings = sugarArrayMerge(
995 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
999 // Load in en_us strings by default
1000 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1001 $loaded_mod_strings = sugarArrayMerge(
1002 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1006 // If we are in debug mode for translating, turn on the prefix now!
1007 if($sugar_config['translation_string_prefix']) {
1008 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1009 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1013 $return_value = $loaded_mod_strings;
1014 if(!isset($mod_strings)){
1015 $mod_strings = $return_value;
1018 $mod_strings = $temp_mod_strings;
1020 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1021 sugar_cache_put($cache_key, $return_value);
1022 return $return_value;
1026 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1027 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1028 * All Rights Reserved.
1029 * Contributor(s): ______________________________________..
1030 * If you are using the current language, do not call this function unless you are loading it for the first time */
1031 function return_mod_list_strings_language($language,$module) {
1032 global $mod_list_strings;
1033 global $sugar_config;
1034 global $currentModule;
1036 $cache_key = "mod_list_str_lang.".$language.$module;
1038 // Check for cached value
1039 $cache_entry = sugar_cache_retrieve($cache_key);
1040 if(!empty($cache_entry))
1042 return $cache_entry;
1045 $language_used = $language;
1046 $temp_mod_list_strings = $mod_list_strings;
1047 $default_language = $sugar_config['default_language'];
1049 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1050 return $mod_list_strings;
1053 // cn: bug 6351 - include en_us if file langpack not available
1054 // cn: bug 6048 - merge en_us with requested language
1055 include("modules/$module/language/en_us.lang.php");
1056 $en_mod_list_strings = array();
1057 if($language_used != $default_language)
1058 $en_mod_list_strings = $mod_list_strings;
1060 if(file_exists("modules/$module/language/$language.lang.php")) {
1061 include("modules/$module/language/$language.lang.php");
1064 if(file_exists("modules/$module/language/$language.lang.override.php")){
1065 include("modules/$module/language/$language.lang.override.php");
1068 if(file_exists("modules/$module/language/$language.lang.php.override")){
1069 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1070 include("modules/$module/language/$language.lang.php.override");
1073 // cn: bug 6048 - merge en_us with requested language
1074 $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1076 // if we still don't have a language pack, then log an error
1077 if(!isset($mod_list_strings)) {
1078 $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})");
1082 $return_value = $mod_list_strings;
1083 $mod_list_strings = $temp_mod_list_strings;
1085 sugar_cache_put($cache_key, $return_value);
1086 return $return_value;
1090 /** This function retrieves a theme's language file and returns the array of strings included.
1091 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1092 * All Rights Reserved.
1093 * Contributor(s): ______________________________________..
1095 function return_theme_language($language, $theme)
1097 global $mod_strings, $sugar_config, $current_language;
1099 $language_used = $language;
1100 $default_language = $sugar_config['default_language'];
1102 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1103 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1104 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1106 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1107 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";
1108 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1110 if(!isset($theme_strings))
1112 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1113 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1114 $language_used = $default_language;
1117 if(!isset($theme_strings))
1119 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1123 // If we are in debug mode for translating, turn on the prefix now!
1124 if($sugar_config['translation_string_prefix'])
1126 foreach($theme_strings as $entry_key=>$entry_value)
1128 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1132 return $theme_strings;
1137 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1138 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1139 * All Rights Reserved.
1140 * Contributor(s): ______________________________________..
1142 function return_session_value_or_default($varname, $default)
1144 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1146 return $_SESSION[$varname];
1153 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1154 * 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.
1155 * @param &$where_clauses - The array to append the clause to
1156 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1157 * @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.
1158 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1159 * All Rights Reserved.
1160 * Contributor(s): ______________________________________..
1162 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1164 if($SQL_name == null)
1166 $SQL_name = $variable_name;
1169 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1171 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1176 * Generate the appropriate SQL based on the where clauses.
1177 * @param $where_clauses - An Array of individual where clauses stored as strings
1178 * @returns string where_clause - The final SQL where clause to be executed.
1179 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1180 * All Rights Reserved.
1181 * Contributor(s): ______________________________________..
1183 function generate_where_statement($where_clauses)
1186 foreach($where_clauses as $clause)
1193 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1198 * determines if a passed string matches the criteria for a Sugar GUID
1199 * @param string $guid
1200 * @return bool False on failure
1202 function is_guid($guid) {
1203 if(strlen($guid) != 36) {
1207 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1216 * A temporary method of generating GUIDs of the correct format for our DB.
1217 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1219 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1220 * All Rights Reserved.
1221 * Contributor(s): ______________________________________..
1223 function create_guid()
1225 $microTime = microtime();
1226 list($a_dec, $a_sec) = explode(" ", $microTime);
1228 $dec_hex = dechex($a_dec* 1000000);
1229 $sec_hex = dechex($a_sec);
1231 ensure_length($dec_hex, 5);
1232 ensure_length($sec_hex, 6);
1236 $guid .= create_guid_section(3);
1238 $guid .= create_guid_section(4);
1240 $guid .= create_guid_section(4);
1242 $guid .= create_guid_section(4);
1245 $guid .= create_guid_section(6);
1251 function create_guid_section($characters)
1254 for($i=0; $i<$characters; $i++)
1256 $return .= dechex(mt_rand(0,15));
1261 function ensure_length(&$string, $length)
1263 $strlen = strlen($string);
1264 if($strlen < $length)
1266 $string = str_pad($string,$length,"0");
1268 else if($strlen > $length)
1270 $string = substr($string, 0, $length);
1274 function microtime_diff($a, $b) {
1275 list($a_dec, $a_sec) = explode(" ", $a);
1276 list($b_dec, $b_sec) = explode(" ", $b);
1277 return $b_sec - $a_sec + $b_dec - $a_dec;
1280 // check if Studio is displayed.
1281 function displayStudioForCurrentUser()
1283 global $current_user;
1284 if ( $current_user->isAdmin() ) {
1294 function displayWorkflowForCurrentUser()
1296 $_SESSION['display_workflow_for_user'] = false;
1300 // return an array with all modules where the user is an admin.
1301 function get_admin_modules_for_user($user) {
1302 $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");
1309 return($user->getDeveloperModules());
1313 function get_workflow_admin_modules_for_user($user){
1314 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1315 return $_SESSION['get_workflow_admin_modules_for_user'];
1319 $workflow_mod_list = array();
1320 foreach($moduleList as $module){
1321 $workflow_mod_list[$module] = $module;
1324 // This list is taken from teh previous version of workflow_utils.php
1325 $workflow_mod_list['Tasks'] = "Tasks";
1326 $workflow_mod_list['Calls'] = "Calls";
1327 $workflow_mod_list['Meetings'] = "Meetings";
1328 $workflow_mod_list['Notes'] = "Notes";
1329 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1330 $workflow_mod_list['Leads'] = "Leads";
1331 $workflow_mod_list['Opportunities'] = "Opportunities";
1334 $workflow_admin_modules = array();
1336 return $workflow_admin_modules;
1338 $actions = ACLAction::getUserActions($user->id);
1339 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1340 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1341 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1342 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1344 foreach ($workflow_mod_list as $key=>$val) {
1345 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1346 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1347 ($user->isDeveloperForModule($key))) {
1348 $workflow_admin_modules[$key] = $val;
1351 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1352 return ($workflow_admin_modules);
1355 // Check if user is admin for at least one module.
1356 function is_admin_for_any_module($user) {
1360 if($user->isAdmin()) {
1367 // Check if user is admin for a specific module.
1368 function is_admin_for_module($user,$module) {
1369 if (!isset($user)) {
1372 if ($user->isAdmin()) {
1380 * Check if user id belongs to a system admin.
1381 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1382 * All Rights Reserved.
1383 * Contributor(s): ______________________________________..
1385 function is_admin($user) {
1390 return $user->isAdmin();
1394 * Return the display name for a theme if it exists.
1395 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1396 * All Rights Reserved.
1397 * Contributor(s): ______________________________________..
1399 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1401 function get_theme_display($theme)
1403 return SugarThemeRegistry::get($theme)->name;
1407 * Return an array of directory names.
1408 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1409 * All Rights Reserved.
1410 * Contributor(s): ______________________________________..
1412 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1414 function get_themes()
1416 return SugarThemeRegistry::availableThemes();
1420 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1421 * Create HTML to display select options in a dropdown list. To be used inside
1422 * of a select statement in a form.
1423 * param $option_list - the array of strings to that contains the option list
1424 * param $selected - the string which contains the default value
1425 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1426 * All Rights Reserved.
1427 * Contributor(s): ______________________________________..
1429 function get_select_options ($option_list, $selected) {
1430 return get_select_options_with_id($option_list, $selected);
1434 * Create HTML to display select options in a dropdown list. To be used inside
1435 * 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.
1436 * param $option_list - the array of strings to that contains the option list
1437 * param $selected - the string which contains the default value
1438 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1439 * All Rights Reserved.
1440 * Contributor(s): ______________________________________..
1442 function get_select_options_with_id ($option_list, $selected_key) {
1443 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1448 * Create HTML to display select options in a dropdown list. To be used inside
1449 * 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.
1450 * param $label_list - the array of strings to that contains the option list
1451 * param $key_list - the array of strings to that contains the values list
1452 * param $selected - the string which contains the default value
1453 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1454 * All Rights Reserved.
1455 * Contributor(s): ______________________________________..
1457 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1458 global $app_strings;
1459 $select_options = "";
1461 //for setting null selection values to human readable --None--
1462 $pattern = "/'0?'></";
1463 $replacement = "''>".$app_strings['LBL_NONE']."<";
1465 $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
1468 if (empty($key_list)) $key_list = array();
1469 //create the type dropdown domain and set the selected value if $opp value already exists
1470 foreach ($key_list as $option_key=>$option_value) {
1472 $selected_string = '';
1473 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1474 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1475 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1477 $selected_string = 'selected ';
1480 $html_value = $option_key;
1482 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1484 $select_options = preg_replace($pattern, $replacement, $select_options);
1485 return $select_options;
1490 * Call this method instead of die().
1491 * Then we call the die method with the error message that is passed in.
1493 function sugar_die($error_message)
1497 die($error_message);
1502 * Create javascript to clear values of all elements in a form.
1503 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1504 * All Rights Reserved.
1505 * Contributor(s): ______________________________________..
1507 function get_clear_form_js () {
1508 $the_script = <<<EOQ
1509 <script type="text/javascript" language="JavaScript">
1510 function clear_form(form) {
1511 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1512 if(typeof(form.advanced) != 'undefined'){
1513 newLoc += '&advanced=' + form.advanced.value;
1515 document.location.href= newLoc;
1524 * Create javascript to set the cursor focus to specific field in a form
1525 * when the screen is rendered. The field name is currently hardcoded into the
1527 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1528 * All Rights Reserved.
1529 * Contributor(s): ______________________________________..
1531 function get_set_focus_js () {
1532 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1533 $the_script = <<<EOQ
1534 <script type="text/javascript" language="JavaScript">
1536 function set_focus() {
1537 if (document.forms.length > 0) {
1538 for (i = 0; i < document.forms.length; i++) {
1539 for (j = 0; j < document.forms[i].elements.length; j++) {
1540 var field = document.forms[i].elements[j];
1541 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1542 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1544 if (field.type == "text") {
1561 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1562 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1563 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1564 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1565 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1566 * the first - so the array is sorted by the last given column first, then the one before ...
1567 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1568 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1569 * All Rights Reserved.
1570 * Contributor(s): ______________________________________..
1572 function array_csort() {
1573 $args = func_get_args();
1574 $marray = array_shift($args);
1577 $msortline = "return(array_multisort(";
1578 foreach ($args as $arg) {
1580 if (is_string($arg)) {
1581 foreach ($marray as $row) {
1582 $sortarr[$i][] = $row[$arg];
1585 $sortarr[$i] = $arg;
1587 $msortline .= "\$sortarr[".$i."],";
1589 $msortline .= "\$marray));";
1596 * Converts localized date format string to jscalendar format
1597 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1598 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1599 * All Rights Reserved.
1600 * Contributor(s): ______________________________________..
1602 function parse_calendardate($local_format) {
1603 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1604 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1605 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1612 function translate($string, $mod='', $selectedValue=''){
1613 //$test_start = microtime();
1614 //static $mod_strings_results = array();
1616 global $current_language;
1618 if(isset($_REQUEST['login_language'])){
1619 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1621 $mod_strings = return_module_language($current_language, $mod);
1624 global $mod_strings;
1628 global $app_strings, $app_list_strings;
1630 if(isset($mod_strings[$string]))
1631 $returnValue = $mod_strings[$string];
1632 else if(isset($app_strings[$string]))
1633 $returnValue = $app_strings[$string];
1634 else if(isset($app_list_strings[$string]))
1635 $returnValue = $app_list_strings[$string];
1636 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1637 $returnValue = $app_list_strings['moduleList'][$string];
1640 //$test_end = microtime();
1642 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1644 // echo("translate results:");
1646 // $total_strings = 0;
1647 // foreach($mod_strings_results as $key=>$value)
1649 // echo("Module $key \t\t time $value \t\t<br>");
1650 // $total_time += $value;
1653 // echo("Total time: $total_time<br>");
1657 if(empty($returnValue)){
1661 if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1662 return $returnValue[$selectedValue];
1665 return $returnValue;
1668 function unTranslateNum($num) {
1670 static $num_grp_sep;
1671 global $current_user, $sugar_config;
1673 if($dec_sep == null) {
1674 $user_dec_sep = $current_user->getPreference('dec_sep');
1675 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1677 if($num_grp_sep == null) {
1678 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1679 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1682 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1683 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1688 function add_http($url) {
1689 if(!preg_match("@://@i", $url)) {
1691 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1695 return "{$scheme}://{$url}";
1702 * returns a default array of XSS tags to clean
1705 function getDefaultXssTags() {
1707 "applet" => "applet",
1712 "frameset" => "frameset",
1713 "iframe" => "iframe",
1714 "import" => "\?import",
1717 "object" => "object",
1718 "script" => "script",
1722 $ret = base64_encode(serialize($tmp));
1728 * Remove potential xss vectors from strings
1729 * @param string str String to search for XSS attack vectors
1730 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1733 function remove_xss($str, $cleanImg=true)
1735 $potentials = clean_xss($str, $cleanImg);
1736 if(is_array($potentials) && !empty($potentials)) {
1737 foreach($potentials as $bad) {
1738 $str = str_replace($bad, "", $str);
1745 * Detects typical XSS attack patterns
1746 * @param string str String to search for XSS attack vectors
1747 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1748 * @return array Array of matches, empty on clean string
1750 function clean_xss($str, $cleanImg=true) {
1751 global $sugar_config;
1753 if(empty($sugar_config['email_xss']))
1754 $sugar_config['email_xss'] = getDefaultXssTags();
1756 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1758 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1759 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1760 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1761 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1763 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1764 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1765 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1766 $css_url = '#url\(.*\.\w+\)#';
1768 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1770 $tagmatches = array();
1772 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1773 foreach($tagmatches[1] as $no => $tag) {
1774 if(in_array($tag, $xsstags)) {
1775 // dangerous tag - take out whole
1776 $matches[] = $tagmatches[0][$no];
1779 $attrmatch = array();
1780 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1781 if(!empty($attrmatch[0])) {
1782 $matches = array_merge($matches, $attrmatch[0]);
1786 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1789 $matches = array_merge($matches,
1790 xss_check_pattern($imgsrc_regex, $str)
1794 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1795 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1797 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1798 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1799 // normalize whitelist
1800 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1801 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1804 foreach($cssUrlMatches[0] as $match) {
1805 $domain = strtolower(substr(strstr($match, "://"), 3));
1806 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1808 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1809 $matches[] = $match;
1814 $matches = array_merge($matches, $cssUrlMatches[0]);
1821 * Helper function used by clean_xss() to parse for known-bad vectors
1822 * @param string pattern Regex pattern to use
1823 * @param string str String to parse for badness
1826 function xss_check_pattern($pattern, $str) {
1827 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1832 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1834 * @param string $str
1835 * @param string $filter which corresponds to a regular expression to use; choices are:
1836 * "STANDARD" ( default )
1846 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1848 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1850 global $sugar_config;
1853 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1854 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1855 "FILE" => '#[^A-Z0-9\-_\.]#i',
1856 "NUMBER" => '#[^0-9\-]#i',
1857 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1858 "PATH_NO_URL" => '#://#i',
1859 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1860 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1861 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1862 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1865 if (preg_match($filters[$filter], $str)) {
1866 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1867 $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1869 if ( $dieOnBadData ) {
1870 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1879 function clean_special_arguments() {
1880 if(isset($_SERVER['PHP_SELF'])) {
1881 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1883 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1884 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1885 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1886 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1887 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1888 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1889 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1890 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1891 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1892 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1893 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1894 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1895 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1896 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1897 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1898 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1899 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1900 clean_superglobals('offset', 'ALPHANUM');
1901 clean_superglobals('return_action');
1902 clean_superglobals('return_module');
1907 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1909 function clean_superglobals($key, $filter = 'STANDARD') {
1910 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1911 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1912 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1915 function set_superglobals($key, $val){
1917 $_POST[$key] = $val;
1918 $_REQUEST[$key] = $val;
1921 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1922 function clean_incoming_data() {
1923 global $sugar_config;
1924 global $RAW_REQUEST;
1926 $RAW_REQUEST = $_REQUEST;
1928 if (get_magic_quotes_gpc() == 1) {
1929 $req = array_map("preprocess_param", $_REQUEST);
1930 $post = array_map("preprocess_param", $_POST);
1931 $get = array_map("preprocess_param", $_GET);
1934 $req = array_map("securexss", $_REQUEST);
1935 $post = array_map("securexss", $_POST);
1936 $get = array_map("securexss", $_GET);
1939 // PHP cannot stomp out superglobals reliably
1940 foreach($post as $k => $v) { $_POST[$k] = $v; }
1941 foreach($get as $k => $v) { $_GET[$k] = $v; }
1942 foreach($req as $k => $v) {
1944 //ensure the keys are safe as well
1947 // Any additional variables that need to be cleaned should be added here
1948 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1949 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1950 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1951 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1952 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1953 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
1954 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
1955 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
1956 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
1957 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
1958 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
1959 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
1960 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
1962 if(isset($_REQUEST['lvso'])){
1963 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
1965 // Clean "offset" and "order_by" parameters in URL
1966 foreach ($_REQUEST as $key => $val) {
1967 if (str_end($key, "_offset")) {
1968 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
1969 set_superglobals($key, $_REQUEST[$key]);
1971 elseif (str_end($key, "_ORDER_BY")) {
1972 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
1973 set_superglobals($key, $_REQUEST[$key]);
1981 // Returns TRUE if $str begins with $begin
1982 function str_begin($str, $begin) {
1983 return (substr($str, 0, strlen($begin)) == $begin);
1986 // Returns TRUE if $str ends with $end
1987 function str_end($str, $end) {
1988 return (substr($str, strlen($str) - strlen($end)) == $end);
1991 function securexss($value) {
1992 if(is_array($value)){
1994 foreach($value as $key=>$val){
1995 $new[$key] = securexss($val);
1999 static $xss_cleanup= array('"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
2000 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2001 $value = preg_replace('/javascript:/i', 'java script:', $value);
2002 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2005 function securexsskey($value, $die=true){
2006 global $sugar_config;
2008 preg_match('/[\'"<>]/', $value, $matches);
2009 if(!empty($matches)){
2011 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2013 unset($_REQUEST[$value]);
2014 unset($_POST[$value]);
2015 unset($_GET[$value]);
2020 function preprocess_param($value){
2021 if(is_string($value)){
2022 if(get_magic_quotes_gpc() == 1){
2023 $value = stripslashes($value);
2026 $value = securexss($value);
2035 function set_register_value($category, $name, $value){
2036 return sugar_cache_put("{$category}:{$name}", $value);
2039 function get_register_value($category,$name){
2040 return sugar_cache_retrieve("{$category}:{$name}");
2043 function clear_register_value($category,$name){
2044 return sugar_cache_clear("{$category}:{$name}");
2046 // this function cleans id's when being imported
2047 function convert_id($string)
2049 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2051 // single quotes are essential here,
2052 // or alternative escape all $ as \$
2054 'return ord($matches[0]);'
2059 * @deprecated use SugarTheme::getImage()
2061 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt)
2063 return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2066 * @deprecated use SugarTheme::getImageURL()
2068 function getImagePath($image_name)
2070 return SugarThemeRegistry::current()->getImageURL($image_name);
2073 function getWebPath($relative_path){
2074 //if it has a :// then it isn't a relative path
2075 if(substr_count($relative_path, '://') > 0) return $relative_path;
2076 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2077 return $relative_path;
2080 function getVersionedPath($path, $additional_attrs='')
2082 if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2083 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2084 if(inDeveloperMode()) {
2086 if(empty($rand)) $rand = mt_rand();
2091 if(is_array($additional_attrs)) {
2092 $additional_attrs = join("|",$additional_attrs);
2094 // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2095 $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2096 // remove / - it confuses some parsers
2097 $str = strtr($str, '/+', '-_');
2098 if(empty($path)) return $str;
2100 return $path . "?v=$str";
2103 function getVersionedScript($path, $additional_attrs='')
2105 return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2108 function getJSPath($relative_path, $additional_attrs='')
2110 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2111 return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2114 function getSWFPath($relative_path, $additional_params=''){
2115 $path = $relative_path;
2116 if (!empty($additional_params)){
2117 $path .= '?' . $additional_params;
2119 if (defined('TEMPLATE_URL')){
2120 $path = TEMPLATE_URL . '/' . $path;
2129 function getSQLDate($date_str)
2131 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2133 if ( strlen($match[2]) == 1)
2135 $match[2] = "0".$match[2];
2137 if ( strlen($match[1]) == 1)
2139 $match[1] = "0".$match[1];
2141 return "{$match[3]}-{$match[1]}-{$match[2]}";
2143 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2145 if ( strlen($match[2]) == 1)
2147 $match[2] = "0".$match[2];
2149 if ( strlen($match[1]) == 1)
2151 $match[1] = "0".$match[1];
2153 return "{$match[3]}-{$match[1]}-{$match[2]}";
2161 function clone_history(&$db, $from_id,$to_id, $to_type)
2166 require_once('include/upload_file.php');
2167 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2169 $location=array('Email'=>"modules/Emails/Email.php",
2170 'Call'=>"modules/Calls/Call.php",
2171 'Meeting'=>"modules/Meetings/Meeting.php",
2172 'Note'=>"modules/Notes/Note.php",
2173 'Tasks'=>"modules/Tasks/Task.php",
2177 foreach($tables as $table=>$bean_class)
2180 if (!class_exists($bean_class))
2182 require_once($location[$bean_class]);
2185 $bProcessingNotes=false;
2186 if ($table=='notes')
2188 $bProcessingNotes=true;
2190 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2191 $results = $db->query($query);
2192 while($row = $db->fetchByAssoc($results))
2194 //retrieve existing record.
2195 $bean= new $bean_class();
2196 $bean->retrieve($row['id']);
2197 //process for new instance.
2198 if ($bProcessingNotes)
2200 $old_note_id=$row['id'];
2201 $old_filename=$bean->filename;
2204 $bean->parent_id=$to_id;
2205 $bean->parent_type=$to_type;
2206 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2208 $bean->contact_id=$to_id;
2210 $bean->update_date_modified = false;
2211 $bean->update_modified_by = false;
2212 if(isset($bean->date_modified))
2213 $bean->date_modified = $timedate->to_db($bean->date_modified);
2214 if(isset($bean->date_entered))
2215 $bean->date_entered = $timedate->to_db($bean->date_entered);
2217 $new_id=$bean->save();
2219 //duplicate the file now. for notes.
2220 if ($bProcessingNotes && !empty($old_filename))
2222 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2224 //reset the values needed for attachment duplication.
2231 function values_to_keys($array)
2233 $new_array = array();
2234 if(!is_array($array))
2238 foreach($array as $arr){
2239 $new_array[$arr] = $arr;
2244 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2246 foreach($tables as $table)
2249 if ($table == 'emails_beans') {
2250 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2252 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2254 $results = $db->query($query);
2255 while($row = $db->fetchByAssoc($results))
2257 $query = "INSERT INTO $table ";
2260 $row[$from_column] = $to_id;
2261 $row['id'] = create_guid();
2262 if ($table=='emails_beans') {
2263 $row['bean_module'] =='Contacts';
2266 foreach($row as $name=>$value)
2272 $values .= "'$value'";
2275 $names .= ', '. $name;
2276 $values .= ", '$value'";
2279 $query .= "($names) VALUES ($values)";
2285 function get_unlinked_email_query($type, $bean) {
2286 global $current_user;
2288 $return_array['select']='SELECT emails.id ';
2289 $return_array['from']='FROM emails ';
2290 $return_array['where']="";
2291 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2293 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2294 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2295 where eear.deleted=0 and eear.email_id not in
2296 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2297 ) derivedemails on derivedemails.email_id = emails.id";
2298 $return_array['join_tables'][0] = '';
2300 if (isset($type) and !empty($type['return_as_array'])) {
2301 return $return_array;
2304 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2308 * Check to see if the number is empty or non-zero
2312 function number_empty($value)
2314 return empty($value) && $value != '0';
2317 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2320 require_once($beanFiles[$bean_name]);
2321 $focus = new $bean_name();
2322 $user_array = array();
2324 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2325 $user_array = get_register_value('select_array', $key );
2329 $db = DBManagerFactory::getInstance();
2331 $temp_result = Array();
2332 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2336 $query .= $where." AND ";
2339 $query .= " {$focus->table_name}.deleted=0";
2341 if ( $order_by != '')
2343 $query .= " order by {$focus->table_name}.{$order_by}";
2346 $GLOBALS['log']->debug("get_user_array query: $query");
2347 $result = $db->query($query, true, "Error filling in user array: ");
2349 if ($add_blank==true){
2350 // Add in a blank row
2351 if($blank_is_none == true) { // set 'blank row' to "--None--"
2352 global $app_strings;
2353 $temp_result[''] = $app_strings['LBL_NONE'];
2355 $temp_result[''] = '';
2359 // Get the id and the name.
2360 while($row = $db->fetchByAssoc($result))
2362 $temp_result[$row['id']] = $row['display'];
2365 $user_array = $temp_result;
2366 set_register_value('select_array', $key ,$temp_result);
2375 * @param unknown_type $listArray
2377 // function parse_list_modules
2378 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2379 function parse_list_modules(&$listArray)
2381 global $modListHeader;
2382 $returnArray = array();
2384 foreach($listArray as $optionName => $optionVal)
2386 if(array_key_exists($optionName, $modListHeader))
2388 $returnArray[$optionName] = $optionVal;
2391 // special case for projects
2392 if(array_key_exists('Project', $modListHeader))
2394 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2397 $acldenied = ACLController::disabledModuleList($listArray,false);
2398 foreach($acldenied as $denied){
2399 unset($returnArray[$denied]);
2401 asort($returnArray);
2403 return $returnArray;
2406 function display_notice($msg = false){
2407 global $error_notice;
2408 //no error notice - lets just display the error to the user
2409 if(!isset($error_notice)){
2410 echo '<br>'.$msg . '<br>';
2412 $error_notice .= $msg . '<br>';
2416 /* checks if it is a number that atleast has the plus at the beggining
2418 function skype_formatted($number){
2419 //kbrill - BUG #15375
2420 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2423 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2425 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2428 function format_skype($number) {
2429 return preg_replace('/[^\+0-9]/','',$number);
2432 function insert_charset_header() {
2433 header('Content-Type: text/html; charset=UTF-8');
2436 function getCurrentURL()
2439 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2444 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2448 function javascript_escape($str) {
2451 for($i = 0; $i < strlen($str); $i++) {
2453 if(ord(substr($str, $i, 1))==10){
2455 }elseif(ord(substr($str, $i, 1))==13){
2459 $new_str .= $str{$i};
2463 $new_str = str_replace("'", "\\'", $new_str);
2468 function js_escape($str, $keep=true){
2469 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2472 $str = javascript_escape($str);
2475 $str = str_replace("'", " ", $str);
2476 $str = str_replace('"', " ", $str);
2481 //end function js_escape
2484 function br2nl($str) {
2485 $regex = "#<[^>]+br.+?>#i";
2486 preg_match_all($regex, $str, $matches);
2488 foreach($matches[0] as $match) {
2489 $str = str_replace($match, "<br>", $str);
2492 $brs = array('<br>','<br/>', '<br />');
2493 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2494 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2495 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2496 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2502 * Private helper function for displaying the contents of a given variable.
2503 * This function is only intended to be used for SugarCRM internal development.
2504 * The ppd stands for Pre Print Die.
2506 function _ppd($mixed)
2512 * Private helper function for displaying the contents of a given variable in
2513 * the Logger. This function is only intended to be used for SugarCRM internal
2514 * development. The pp stands for Pre Print.
2515 * @param $mixed var to print_r()
2516 * @param $die boolean end script flow
2517 * @param $displayStackTrace also show stack trace
2519 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2520 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2522 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2526 $mix = print_r($mixed, true); // send print_r() output to $mix
2527 $stack = debug_backtrace();
2529 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2530 $GLOBALS['log']->$loglevel($mix);
2531 if($displayStackTrace) {
2532 foreach($stack as $position) {
2533 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2537 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2538 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2546 * private helper function to quickly show the major, direct, field attributes of a given bean.
2547 * The ppf stands for Pre[formatted] Print Focus [object]
2548 * @param object bean The focus bean
2550 function _ppf($bean, $die=false) {
2556 * Private helper function for displaying the contents of a given variable.
2557 * This function is only intended to be used for SugarCRM internal development.
2558 * The pp stands for Pre Print.
2560 function _pp($mixed)
2565 * Private helper function for displaying the contents of a given variable.
2566 * This function is only intended to be used for SugarCRM internal development.
2567 * The pp stands for Pre Print.
2569 function _pstack_trace($mixed=NULL)
2574 * Private helper function for displaying the contents of a given variable.
2575 * This function is only intended to be used for SugarCRM internal development.
2576 * The pp stands for Pre Print Trace.
2578 function _ppt($mixed, $textOnly=false)
2583 * Private helper function for displaying the contents of a given variable.
2584 * This function is only intended to be used for SugarCRM internal development.
2585 * The pp stands for Pre Print Trace Die.
2587 function _pptd($mixed)
2592 * Private helper function for decoding javascript UTF8
2593 * This function is only intended to be used for SugarCRM internal development.
2595 function decodeJavascriptUTF8($str) {
2599 * Will check if a given PHP version string is supported (tested on this ver),
2600 * unsupported (results unknown), or invalid (something will break on this
2601 * ver). Do not pass in any pararameter to default to a check against the
2602 * current environment's PHP version.
2604 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2606 function check_php_version($sys_php_version = '') {
2607 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2608 // versions below $min_considered_php_version considered invalid by default,
2609 // versions equal to or above this ver will be considered depending
2610 // on the rules that follow
2611 $min_considered_php_version = '5.2.1';
2613 // only the supported versions,
2614 // should be mutually exclusive with $invalid_php_versions
2615 $supported_php_versions = array (
2616 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2619 // invalid versions above the $min_considered_php_version,
2620 // should be mutually exclusive with $supported_php_versions
2622 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2623 $invalid_php_versions = array('5.2.7');
2625 // default unsupported
2628 // versions below $min_considered_php_version are invalid
2629 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2633 // supported version check overrides default unsupported
2634 foreach($supported_php_versions as $ver) {
2635 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2641 // invalid version check overrides default unsupported
2642 foreach($invalid_php_versions as $ver) {
2643 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2649 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2650 //and the php version contains 'rh' characters
2651 if(strpos($sys_php_version, 'rh') !== false) {
2659 * Will check if a given IIS version string is supported (tested on this ver),
2660 * unsupported (results unknown), or invalid (something will break on this
2663 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2665 function check_iis_version($sys_iis_version = '') {
2667 $server_software = $_SERVER["SERVER_SOFTWARE"];
2669 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2670 $iis_version = $out[1][0];
2672 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2674 // versions below $min_considered_iis_version considered invalid by default,
2675 // versions equal to or above this ver will be considered depending
2676 // on the rules that follow
2677 $min_considered_iis_version = '6.0';
2679 // only the supported versions,
2680 // should be mutually exclusive with $invalid_iis_versions
2681 $supported_iis_versions = array ('6.0', '7.0',);
2682 $unsupported_iis_versions = array();
2683 $invalid_iis_versions = array('5.0',);
2685 // default unsupported
2688 // versions below $min_considered_iis_version are invalid
2689 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2693 // supported version check overrides default unsupported
2694 foreach($supported_iis_versions as $ver) {
2695 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2701 // unsupported version check overrides default unsupported
2702 foreach($unsupported_iis_versions as $ver) {
2703 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2709 // invalid version check overrides default unsupported
2710 foreach($invalid_iis_versions as $ver) {
2711 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2720 function pre_login_check(){
2721 global $action, $login_error;
2722 if(!empty($action)&& $action == 'Login'){
2724 if(!empty($login_error)){
2725 $login_error = htmlentities($login_error);
2726 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2727 $_SESSION['login_error'] = $login_error;
2729 function set_focus() {}
2730 if(document.getElementById("post_error")) {
2731 document.getElementById("post_error").innerHTML="'. $login_error. '";
2732 document.getElementById("cant_login").value=1;
2733 document.getElementById("login_button").disabled = true;
2734 document.getElementById("user_name").disabled = true;
2735 //document.getElementById("user_password").disabled = true;
2744 function sugar_cleanup($exit = false) {
2745 static $called = false;
2748 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2749 chdir(realpath(dirname(__FILE__) . '/..'));
2750 global $sugar_config;
2751 require_once('include/utils/LogicHook.php');
2752 LogicHook::initialize();
2753 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2755 //added this check to avoid errors during install.
2756 if (empty($sugar_config['dbconfig'])) {
2757 if ($exit) exit; else return;
2760 if (!class_exists('Tracker', true)) {
2761 require_once 'modules/Trackers/Tracker.php';
2764 // Now write the cached tracker_queries
2765 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2766 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2767 $GLOBALS['current_user']->savePreferencesToDB();
2770 //check to see if this is not an `ajax call AND the user preference error flag is set
2772 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2773 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2774 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2775 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2778 global $app_strings;
2779 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2780 $err_mess = $app_strings['ERROR_USER_PREFS'];
2781 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2784 ajaxStatus.flashStatus('$err_mess',7000);
2790 if(class_exists('DBManagerFactory')) {
2791 $db = DBManagerFactory::getInstance();
2799 register_shutdown_function('sugar_cleanup');
2803 check_logic_hook - checks to see if your custom logic is in the logic file
2804 if not, it will add it. If the file isn't built yet, it will create the file
2807 function check_logic_hook_file($module_name, $event, $action_array){
2808 require_once('include/utils/logic_utils.php');
2811 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2813 $hook_array = get_hook_array($module_name);
2815 if(check_existing_element($hook_array, $event, $action_array)==true){
2816 //the hook at hand is present, so do nothing
2821 if(!empty($hook_array[$event]))
2823 $logic_count = count($hook_array[$event]);
2826 if($action_array[0]==""){
2827 $action_array[0] = $logic_count + 1;
2829 $hook_array[$event][] = $action_array;
2832 //end if the file exists already
2835 if($action_array[0]==""){
2836 $action_array[0] = 1;
2838 $hook_array = array();
2839 $hook_array[$event][] = $action_array;
2840 //end if else file exists already
2842 if($add_logic == true){
2844 //reorder array by element[0]
2845 //$hook_array = reorder_array($hook_array, $event);
2846 //!!!Finish this above TODO
2848 $new_contents = replace_or_add_logic_type($hook_array);
2849 write_logic_file($module_name, $new_contents);
2851 //end if add_element is true
2854 //end function check_logic_hook_file
2857 function remove_logic_hook($module_name, $event, $action_array) {
2858 require_once('include/utils/logic_utils.php');
2861 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2862 // The file exists, let's make sure the hook is there
2863 $hook_array = get_hook_array($module_name);
2865 if(check_existing_element($hook_array, $event, $action_array)==true){
2866 // The hook is there, time to take it out.
2868 foreach ( $hook_array[$event] as $i => $hook ) {
2869 // We don't do a full comparison below just in case the filename changes
2870 if ( $hook[0] == $action_array[0]
2871 && $hook[1] == $action_array[1]
2872 && $hook[3] == $action_array[3]
2873 && $hook[4] == $action_array[4] ) {
2874 unset($hook_array[$event][$i]);
2878 $new_contents = replace_or_add_logic_type($hook_array);
2879 write_logic_file($module_name, $new_contents);
2885 function display_stack_trace($textOnly=false){
2887 $stack = debug_backtrace();
2889 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2897 foreach($stack as $item) {
2903 if(isset($item['file']))
2904 $file = $item['file'];
2905 if(isset($item['class']))
2906 $class = $item['class'];
2907 if(isset($item['line']))
2908 $line = $item['line'];
2909 if(isset($item['function']))
2910 $function = $item['function'];
2914 $out .= '<font color="black"><b>';
2920 $out .= '</b></font><font color="blue">';
2923 $out .= "[L:{$line}]";
2926 $out .= '</font><font color="red">';
2929 $out .= "({$class}:{$function})";
2932 $out .= '</font><br>';
2944 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2945 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2946 $halt_script = true;
2948 case 2048: return; //depricated we have lots of these ignore them
2951 if ( error_reporting() & E_NOTICE ) {
2952 $halt_script = false;
2958 case E_USER_WARNING:
2959 case E_COMPILE_WARNING:
2960 case E_CORE_WARNING:
2963 $halt_script = false;
2968 case E_COMPILE_ERROR:
2972 $type = "Fatal Error";
2977 $type = "Parse Error";
2981 //don't know what it is might not be so bad
2982 $halt_script = false;
2983 $type = "Unknown Error ($errno)";
2986 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
2988 display_stack_trace();
2998 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3000 set_error_handler('StackTraceErrorHandler');
3002 function get_sub_cookies($name){
3004 if(isset($_COOKIE[$name])){
3005 $subs = explode('#', $_COOKIE[$name]);
3006 foreach($subs as $cookie){
3007 if(!empty($cookie)){
3008 $cookie = explode('=', $cookie);
3010 $cookies[$cookie[0]] = $cookie[1];
3019 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3021 if(!empty($sub_object_array)){
3023 foreach($sub_object_array as $sub_object){
3025 //run_second level is set to true if you need to remove sub-sub components
3026 if($run_second_level==true){
3028 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3030 //end if run_second_level is true
3032 $sub_object->mark_deleted($sub_object->id);
3033 //end foreach sub component
3035 //end if this is not empty
3038 //end function mark_delete_components
3042 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3044 function return_bytes($val)
3047 $last = strtolower($val{strlen($val)-1});
3051 // The 'G' modifier is available since PHP 5.1.0
3064 * Adds the href HTML tags around any URL in the $string
3066 function url2html($string) {
3068 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3069 return $return_string;
3071 // End customization by Julian
3074 * tries to determine whether the Host machine is a Windows machine
3076 function is_windows() {
3077 static $is_windows = null;
3078 if (!isset($is_windows)) {
3079 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3085 * equivalent for windows filesystem for PHP's is_writable()
3086 * @param string file Full path to the file/dir
3087 * @return bool true if writable
3089 function is_writable_windows($file) {
3090 if($file{strlen($file)-1}=='/') {
3091 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3094 // the assumption here is that Windows has an inherited permissions scheme
3095 // any file that is a descendant of an unwritable directory will inherit
3096 // that property and will trigger a failure below.
3101 $file = str_replace("/", '\\', $file);
3103 if(file_exists($file)) {
3104 if (!($f = @sugar_fopen($file, 'r+')))
3110 if(!($f = @sugar_fopen($file, 'w')))
3119 * best guesses Timezone based on webserver's TZ settings
3121 function lookupTimezone($userOffset = 0)
3123 return TimeDate::guessTimezone($userOffset);
3126 function convert_module_to_singular($module_array){
3129 foreach($module_array as $key => $value){
3130 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3132 if($value=="Cases") {
3133 $module_array[$key] = "Case";
3135 if($key=="projecttask"){
3136 $module_array['ProjectTask'] = "Project Task";
3137 unset($module_array[$key]);
3141 return $module_array;
3143 //end function convert_module_to_singular
3147 * Given the bean_name which may be plural or singular return the singular
3148 * bean_name. This is important when you need to include files.
3150 function get_singular_bean_name($bean_name){
3151 global $beanFiles, $beanList;
3152 if(array_key_exists($bean_name, $beanList)){
3153 return $beanList[$bean_name];
3161 * Given the potential module name (singular name, renamed module name)
3162 * Return the real internal module name.
3164 function get_module_from_singular($singular) {
3166 // find the internal module name for a singular name
3167 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3169 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3171 foreach ($singular_modules as $mod_name=>$sin_name) {
3172 if ($singular == $sin_name and $mod_name != $sin_name) {
3178 // find the internal module name for a renamed module
3179 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3181 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3183 foreach ($moduleList as $mod_name=>$name) {
3184 if ($singular == $name and $mod_name != $name) {
3190 // if it's not a singular name, nor a renamed name, return the original value
3194 function get_label($label_tag, $temp_module_strings){
3195 global $app_strings;
3196 if(!empty($temp_module_strings[$label_tag])){
3198 $label_name = $temp_module_strings[$label_tag];
3200 if(!empty($app_strings[$label_tag])){
3201 $label_name = $app_strings[$label_tag];
3203 $label_name = $label_tag;
3208 //end function get_label
3212 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3214 $rel_list = array();
3216 foreach($focus->relationship_fields as $rel_key => $rel_value){
3217 if($rel_value == $relationship_name){
3218 $temp_bean = get_module_info($tar_rel_module);
3219 // echo $focus->$rel_key;
3220 $temp_bean->retrieve($focus->$rel_key);
3221 if($temp_bean->id!=""){
3223 $rel_list[] = $temp_bean;
3229 foreach($focus->field_defs as $field_name => $field_def){
3230 //Check if the relationship_name matches a "relate" field
3231 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3232 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3233 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3234 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3236 $temp_bean = get_module_info($tar_rel_module);
3237 // echo $focus->$field_def['id_name'];
3238 $temp_bean->retrieve($focus->$field_def['id_name']);
3239 if($temp_bean->id!=""){
3241 $rel_list[] = $temp_bean;
3244 //Check if the relationship_name matches a "link" in a relate field
3245 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3246 $temp_bean = get_module_info($tar_rel_module);
3247 // echo $focus->$rel_value['id_name'];
3248 $temp_bean->retrieve($focus->$rel_value['id_name']);
3249 if($temp_bean->id!=""){
3251 $rel_list[] = $temp_bean;
3257 // special case for unlisted parent-type relationships
3258 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3259 $temp_bean = get_module_info($tar_rel_module);
3260 $temp_bean->retrieve($focus->parent_id);
3261 if($temp_bean->id!=""){
3262 $rel_list[] = $temp_bean;
3269 //end function search_filter_rel_info
3272 function get_module_info($module_name){
3276 //Get dictionary and focus data for module
3277 $vardef_name = $beanList[$module_name];
3279 if($vardef_name=="aCase"){
3280 $class_name = "Case";
3282 $class_name = $vardef_name;
3285 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3289 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3291 $module_bean = new $vardef_name();
3292 return $module_bean;
3293 //end function get_module_table
3297 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3299 * @param string $moduleName
3301 function get_valid_bean_name($module_name){
3304 $vardef_name = $beanList[$module_name];
3305 if($vardef_name=="aCase"){
3306 $bean_name = "Case";
3308 $bean_name = $vardef_name;
3315 function checkAuthUserStatus(){
3322 * This function returns an array of phpinfo() results that can be parsed and
3323 * used to figure out what version we run, what modules are compiled in, etc.
3324 * @param $level int info level constant (1,2,4,8...64);
3325 * @return $returnInfo array array of info about the PHP environment
3326 * @author original by "code at adspeed dot com" Fron php.net
3327 * @author customized for Sugar by Chris N.
3329 function getPhpInfo($level=-1) {
3330 /** Name (constant) Value Description
3331 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3332 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3333 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3334 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3335 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3336 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3337 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3338 INFO_ALL -1 Shows all of the above. This is the default value.
3342 $phpinfo = ob_get_contents();
3345 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3346 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3347 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3348 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3351 $returnInfo = array();
3353 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3354 $returnInfo['PHP Version'] = $version[1];
3358 for ($i=1; $i<count($parsedInfo); $i++) {
3359 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3360 $vName = trim($match[1]);
3361 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3363 foreach ($parsedInfo2 AS $vOne) {
3364 $vPat = '<info>([^<]+)<\/info>';
3365 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3366 $vPat2 = "/$vPat\s*$vPat/";
3368 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3369 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3370 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3371 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3383 * This function will take a string that has tokens like {0}, {1} and will replace
3384 * those tokens with the args provided
3385 * @param $format string to format
3386 * @param $args args to replace
3387 * @return $result a formatted string
3389 function string_format($format, $args){
3393 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3394 * IN () fails and IN ('') works.
3396 if (count($args) == 1)
3399 $singleArgument = current($args);
3400 if (empty($singleArgument))
3402 return str_replace("{0}", "''", $result);
3407 for($i = 0; $i < count($args); $i++){
3408 $result = str_replace('{'.$i.'}', $args[$i], $result);
3414 * Generate a string for displaying a unique identifier that is composed
3415 * of a system_id and number. This is use to allow us to generate quote
3416 * numbers using a DB auto-increment key from offline clients and still
3417 * have the number be unique (since it is modified by the system_id.
3419 * @param $num of bean
3420 * @param $system_id from system
3421 * @return $result a formatted string
3423 function format_number_display($num, $system_id){
3424 global $sugar_config;
3425 if(isset($num) && !empty($num)){
3426 $num=unformat_number($num);
3427 if(isset($system_id) && $system_id == 1){
3428 return sprintf("%d", $num);
3431 return sprintf("%d-%d", $num, $system_id);
3435 function checkLoginUserStatus(){
3439 * This function will take a number and system_id and format
3440 * @param $url URL containing host to append port
3441 * @param $port the port number - if '' is passed, no change to url
3442 * @return $resulturl the new URL with the port appended to the host
3444 function appendPortToHost($url, $port)
3448 // if no port, don't change the url
3451 $split = explode("/", $url);
3452 //check if it starts with http, in case they didn't include that in url
3453 if(str_begin($url, 'http'))
3455 //third index ($split[2]) will be the host
3456 $split[2] .= ":".$port;
3458 else // otherwise assumed to start with host name
3460 //first index ($split[0]) will be the host
3461 $split[0] .= ":".$port;
3464 $resulturl = implode("/", $split);
3471 * Singleton to return JSON object
3472 * @return JSON object
3474 function getJSONobj() {
3475 static $json = null;
3477 require_once('include/JSON.php');
3478 $json = new JSON(JSON_LOOSE_TYPE);
3483 require_once('include/utils/db_utils.php');
3486 * Set default php.ini settings for entry points
3488 function setPhpIniSettings() {
3490 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3492 if(function_exists('gzclose') && headers_sent() == false) {
3493 ini_set('zlib.output_compression', 1);
3497 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3499 /*if(function_exists('mb_strlen')) {
3500 ini_set('mbstring.func_overload', 7);
3501 ini_set('mbstring.internal_encoding', 'UTF-8');
3505 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3506 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3507 $backtrack_limit = ini_get('pcre.backtrack_limit');
3508 if(!empty($backtrack_limit)) {
3509 ini_set('pcre.backtrack_limit', '-1');
3514 * like array_merge() but will handle array elements that are themselves arrays;
3515 * PHP's version just overwrites the element with the new one.
3517 * @internal Note that this function deviates from the internal array_merge()
3518 * functions in that it does does not treat numeric keys differently
3519 * than string keys. Additionally, it deviates from
3520 * array_merge_recursive() by not creating an array when like values
3523 * @param array gimp the array whose values will be overloaded
3524 * @param array dom the array whose values will pwn the gimp's
3525 * @return array beaten gimp
3527 function sugarArrayMerge($gimp, $dom) {
3528 if(is_array($gimp) && is_array($dom)) {
3529 foreach($dom as $domKey => $domVal) {
3530 if(array_key_exists($domKey, $gimp)) {
3531 if(is_array($domVal)) {
3533 foreach ( $domVal as $domArrKey => $domArrVal )
3534 $tempArr[$domArrKey] = $domArrVal;
3535 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3536 if ( !array_key_exists($gimpArrKey, $tempArr) )
3537 $tempArr[$gimpArrKey] = $gimpArrVal;
3538 $gimp[$domKey] = $tempArr;
3540 $gimp[$domKey] = $domVal;
3543 $gimp[$domKey] = $domVal;
3547 // if the passed value for gimp isn't an array, then return the $dom
3548 elseif(is_array($dom))
3555 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3557 * @param array gimp the array whose values will be overloaded
3558 * @param array dom the array whose values will pwn the gimp's
3559 * @return array beaten gimp
3561 function sugarArrayMergeRecursive($gimp, $dom) {
3562 if(is_array($gimp) && is_array($dom)) {
3563 foreach($dom as $domKey => $domVal) {
3564 if(array_key_exists($domKey, $gimp)) {
3565 if(is_array($domVal) && is_array($gimp[$domKey])) {
3566 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3568 $gimp[$domKey] = $domVal;
3571 $gimp[$domKey] = $domVal;
3575 // if the passed value for gimp isn't an array, then return the $dom
3576 elseif(is_array($dom))
3583 * finds the correctly working versions of PHP-JSON
3584 * @return bool True if NOT found or WRONG version
3586 function returnPhpJsonStatus() {
3587 if(function_exists('json_encode')) {
3588 $phpInfo = getPhpInfo(8);
3589 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3591 return true; // not found
3596 * getTrackerSubstring
3598 * Returns a [number]-char or less string for the Tracker to display in the header
3599 * based on the tracker_max_display_length setting in config.php. If not set,
3600 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3602 * @param string name field for a given Object
3603 * @return string [number]-char formatted string if length of string exceeds the max allowed
3605 function getTrackerSubstring($name) {
3606 static $max_tracker_item_length;
3609 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3610 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3612 global $sugar_config;
3614 if(!isset($max_tracker_item_length)) {
3615 if(isset($sugar_config['tracker_max_display_length'])) {
3616 $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;
3618 $max_tracker_item_length = 15;
3622 if($strlen > $max_tracker_item_length) {
3623 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length, "UTF-8");
3630 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3631 $where_clauses= array();
3633 $table_name=$bean->object_name;
3634 foreach ($field_list[$module] as $field=>$parms) {
3635 if(isset($values[$field]) && $values[$field] != "") {
3637 if (!empty($parms['operator'])) {
3638 $operator=$parms['operator'];
3640 if (is_array($values[$field])) {
3643 foreach ($values[$field] as $key => $val) {
3644 if ($val != ' ' and $val != '') {
3645 if (!empty($field_value)) {
3648 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3652 $field_value=$GLOBALS['db']->quote($values[$field]);
3654 //set db_fields array.
3655 if (!isset($parms['db_field']) ) {
3656 $parms['db_field'] = array($field);
3658 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3659 global $current_user;
3660 $field_value = $GLOBALS['db']->quote($current_user->id);
3666 if ($field_value != '') {
3668 foreach ($parms['db_field'] as $db_field) {
3669 if (strstr($db_field,'.')===false) {
3670 $db_field=$bean->table_name.".".$db_field;
3672 if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3673 $db_field='upper('.$db_field.")";
3674 $field_value=strtoupper($field_value);
3678 if (!empty($where)) {
3681 switch (strtolower($operator)) {
3683 $where .= $db_field . " like '".$field_value.$like_char."'";
3686 $where .= $db_field . " in (".$field_value.')';
3689 $where .= $db_field . " = '".$field_value ."'";
3694 if (!empty($where)) {
3696 array_push($where_clauses, '( '.$where.' )');
3698 array_push($where_clauses, $where);
3703 if ($add_custom_fields) {
3704 require_once('modules/DynamicFields/DynamicField.php');
3705 $bean->setupCustomFields($module);
3706 $bean->custom_fields->setWhereClauses($where_clauses);
3708 return $where_clauses;
3711 function add_quotes($str) {
3716 * This function will rebuild the config file
3717 * @param $sugar_config
3718 * @param $sugar_version
3719 * @return bool true if successful
3721 function rebuildConfigFile($sugar_config, $sugar_version) {
3722 // add defaults to missing values of in-memory sugar_config
3723 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3724 // need to override version with default no matter what
3725 $sugar_config['sugar_version'] = $sugar_version;
3727 ksort( $sugar_config );
3729 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3738 * getJavascriptSiteURL
3739 * This function returns a URL for the client javascript calls to access
3740 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3741 * are used to access the site. Thus, the hostname in the URL returned may
3742 * not always match that of $sugar_config['site_url']. Basically, the
3743 * assumption is that however the user accessed the website is how they
3744 * will continue to with subsequent javascript requests. If the variable
3745 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3746 * @return $site_url The url used to refer to the website
3748 function getJavascriptSiteURL() {
3749 global $sugar_config;
3750 if(!empty($_SERVER['HTTP_REFERER'])) {
3751 $url = parse_url($_SERVER['HTTP_REFERER']);
3752 $replacement_url = $url['scheme']."://".$url['host'];
3753 if(!empty($url['port']))
3754 $replacement_url .= ':'.$url['port'];
3755 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3757 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3758 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3759 $site_url = preg_replace('/^http\:/','https:',$site_url);
3762 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3766 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3767 function add_squotes($str) {
3768 return "'" . $str . "'";
3772 // recursive function to count the number of levels within an array
3773 function array_depth($array, $depth_count=-1, $depth_array=array()){
3775 if (is_array($array)){
3776 foreach ($array as $key => $value){
3777 $depth_array[] = array_depth($value, $depth_count);
3781 return $depth_count;
3783 foreach ($depth_array as $value){
3784 $depth_count = $value > $depth_count ? $value : $depth_count;
3786 return $depth_count;
3790 * Creates a new Group User
3791 * @param string $name Name of Group User
3792 * @return string GUID of new Group User
3794 function createGroupUser($name) {
3797 $group = new User();
3798 $group->user_name = $name;
3799 $group->last_name = $name;
3800 $group->is_group = 1;
3801 $group->deleted = 0;
3802 $group->status = 'Active'; // cn: bug 6711
3803 $group->setPreference('timezone', TimeDate::userTimezone());
3810 * Helper function to locate an icon file given only a name
3811 * Searches through the various paths for the file
3812 * @param string iconFileName The filename of the icon
3813 * @return string Relative pathname of the located icon, or '' if not found
3816 function _getIcon($iconFileName)
3819 $iconName = "icon_{$iconFileName}.gif";
3820 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3822 //First try un-ucfirst-ing the icon name
3823 if ( empty($iconFound) )
3824 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3825 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3827 //Next try removing the icon prefix
3828 if ( empty($iconFound) )
3829 $iconName = "{$iconFileName}.gif";
3830 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3832 if ( empty($iconFound) )
3838 * Function to grab the correct icon image for Studio
3839 * @param string $iconFileName Name of the icon file
3840 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3841 * @param string $width Width of image
3842 * @param string $height Height of image
3843 * @param string $align Alignment of image
3844 * @param string $alt Alt tag of image
3845 * @return string $string <img> tag with corresponding image
3848 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
3850 global $app_strings, $theme;
3852 $iconName = _getIcon($iconFileName);
3853 if(empty($iconName)){
3854 $iconName = _getIcon($altFileName);
3855 if (empty($iconName))
3857 return $app_strings['LBL_NO_IMAGE'];
3860 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3864 * Function to grab the correct icon image for Dashlets Dialog
3865 * @param string $filename Location of the icon file
3866 * @param string $module Name of the module to fall back onto if file does not exist
3867 * @param string $width Width of image
3868 * @param string $height Height of image
3869 * @param string $align Alignment of image
3870 * @param string $alt Alt tag of image
3871 * @return string $string <img> tag with corresponding image
3874 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
3875 global $app_strings, $theme;
3876 $iconName = _getIcon($module . "_32");
3877 if (empty($iconName))
3879 $iconName = _getIcon($module);
3881 if(empty($iconName)){
3882 return $app_strings['LBL_NO_IMAGE'];
3884 return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3887 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3888 function html_entity_decode_utf8($string)
3891 // replace numeric entities
3892 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3893 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3894 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
3895 // replace literal entities
3896 if (!isset($trans_tbl))
3898 $trans_tbl = array();
3899 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3900 $trans_tbl[$key] = utf8_encode($val);
3902 return strtr($string, $trans_tbl);
3905 // Returns the utf string corresponding to the unicode value
3906 function code2utf($num)
3908 if ($num < 128) return chr($num);
3909 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3910 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3911 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3915 function str_split_php4($string, $length = 1) {
3916 $string_length = strlen($string);
3919 if ($length > $string_length) {
3920 // use the string_length as the string is shorter than the length
3921 $length = $string_length;
3923 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3924 $return[] = substr($string, $cursor, $length);
3929 if (version_compare(phpversion(), '5.0.0', '<')) {
3930 function str_split($string, $length = 1) {
3931 return str_split_php4($string, $length);
3936 * @deprecated use DBManagerFactory::isFreeTDS
3938 function is_freetds()
3940 return DBManagerFactory::isFreeTDS();
3944 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3946 * @todo this won't work completely right until we impliment css compression and combination
3947 * for now, we'll just include the last css file found.
3949 * @return chart.css file to use
3951 function chartStyle()
3953 return SugarThemeRegistry::current()->getCSSURL('chart.css');
3957 * Chart dashlet helper functions that returns the correct XML color file for charts,
3958 * dependent on the current theme.
3960 * @return sugarColors.xml to use
3962 function chartColors()
3964 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
3965 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
3966 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
3968 /* End Chart Dashlet helper functions */
3971 * This function is designed to set up the php enviroment
3972 * for AJAX requests.
3975 function ajaxInit() {
3976 ini_set('display_errors', 'false');
3980 * Returns an absolute path from the given path, determining if it is relative or absolute
3982 * @param string $path
3985 function getAbsolutePath(
3987 $currentServer = false
3990 $path = trim($path);
3992 // try to match absolute paths like \\server\share, /directory or c:\
3993 if ( ( substr($path,0,2) == '\\\\' )
3994 || ( $path[0] == '/' )
3995 || preg_match('/^[A-z]:/i',$path)
3999 return getcwd().'/'.$path;
4003 * Returns the bean object of the given module
4005 * @deprecated use SugarModule::loadBean() instead
4006 * @param string $module
4013 return SugarModule::get($module)->loadBean();
4018 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4020 function isTouchScreen()
4022 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4024 // first check if we have forced use of the touch enhanced interface
4025 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4029 // next check if we should use the touch interface with our device
4030 if ( strpos($ua, 'ipad') !== false ) {
4038 * Returns the shortcut keys to access the shortcut links. Shortcut
4039 * keys vary depending on browser versions and operating systems.
4040 * @return String value of the shortcut keys
4042 function get_alt_hot_key() {
4044 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4045 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4046 $isMac = strpos($ua, 'mac') !== false;
4047 $isLinux = strpos($ua, 'linux') !== false;
4049 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4050 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4051 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4054 return $isMac ? 'Ctrl+' : 'Alt+';
4057 function can_start_session(){
4058 if(!empty($_GET['PHPSESSID'])) {
4061 $session_id = session_id();
4062 return empty($session_id) ? true : false;
4065 function load_link_class($properties){
4067 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4068 require_once($properties['link_file']);
4069 $class = $properties['link_class'];
4075 function inDeveloperMode()
4077 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4081 * Filter the protocol list for inbound email accounts.
4083 * @param array $protocol
4085 function filterInboundEmailPopSelection($protocol)
4087 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4089 if( isset($protocol['pop3']) )
4090 unset($protocol['pop3']);
4093 $protocol['pop3'] = 'POP3';
4099 * The function is used because currently we are not supporting mbstring.func_overload
4100 * 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.
4101 * 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.
4102 * @returns the substred strings.
4104 function sugar_substr($string, $length, $charset='UTF-8')
4106 if(mb_strlen($string,$charset) > $length) {
4107 $string = trim(mb_substr(trim($string),0,$length,$charset));
4113 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4114 * This will work even without setting the mbstring.*encoding
4116 function sugar_ucfirst($string, $charset='UTF-8') {
4117 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4124 function unencodeMultienum($string) {
4125 if (is_array($string))
4129 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4130 $string = substr(substr($string, 1), 0, strlen($string) -2);
4133 return explode('^,^', $string);
4136 function encodeMultienumValue($arr) {
4137 if (!is_array($arr))
4143 $string = "^" . implode('^,^', $arr) . "^";
4149 * create_export_query is used for export and massupdate
4150 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4151 * This function will correct the where clause and output necessary join condition for them
4152 * @param $module: the module name
4153 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4154 * @param $where: where clauses
4155 * @return $ret_array['where']: corrected where clause
4156 * @return $ret_array['join']: extra join condition
4158 function create_export_query_relate_link_patch($module, $searchFields, $where){
4159 if(file_exists('modules/'.$module.'/SearchForm.html')){
4160 $ret_array['where'] = $where;
4163 $seed = loadBean($module);
4164 foreach($seed->field_defs as $name=>$field)
4167 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4168 $seed->load_relationship($field['link']);
4170 if(empty($join_type))
4172 $params['join_type'] = ' LEFT JOIN ';
4176 $params['join_type'] = $join_type;
4178 if(isset($data['join_name']))
4180 $params['join_table_alias'] = $field['join_name'];
4184 $params['join_table_alias'] = 'join_'.$field['name'];
4187 if(isset($data['join_link_name']))
4189 $params['join_table_link_alias'] = $field['join_link_name'];
4193 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4195 $join = $seed->$field['link']->getJoin($params, true);
4196 $join_table_alias = 'join_'.$field['name'];
4197 if(isset($field['db_concat_fields'])){
4198 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4199 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4201 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4205 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4210 * 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.
4211 * @Depends on QuickRepairAndRebuild.php
4212 * @Relate bug 30642 ,23177
4214 function clearAllJsAndJsLangFilesWithoutOutput(){
4215 global $current_language , $mod_strings;
4216 $MBmodStrings = $mod_strings;
4217 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4218 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4219 $repair = new RepairAndClear();
4220 $repair->module_list = array();
4221 $repair->show_output = false;
4222 $repair->clearJsLangFiles();
4223 $repair->clearJsFiles();
4224 $mod_strings = $MBmodStrings;
4228 * This function will allow you to get a variable value from query string
4230 function getVariableFromQueryString($variable, $string){
4232 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4242 * should_hide_iframes
4243 * This is a helper method to determine whether or not to show iframes (My Sites) related
4244 * information in the application.
4246 * @return boolean flag indicating whether or not iframes module should be hidden
4248 function should_hide_iframes() {
4249 //Remove the MySites module
4250 if(file_exists('modules/iFrames/iFrame.php')) {
4251 if(!class_exists("iFrame")) {
4252 require_once('modules/iFrames/iFrame.php');
4260 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4262 * @param string $version
4263 * @return string RC, BETA, GA
4265 function getVersionStatus($version){
4266 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4267 return strtoupper($matches[1]);
4274 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4275 * 5.5.1RC1 then return 5.5.1
4277 * @param string $version
4280 function getMajorMinorVersion($version){
4281 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4282 $version = $matches2[1];
4283 $arr = explode('.', $version);
4284 if(count($arr) > 2){
4286 $version = substr($version, 0, 3);
4294 * Return string composed of seconds & microseconds of current time, without dots
4297 function sugar_microtime()
4299 $now = explode(' ', microtime());
4300 $unique_id = $now[1].str_replace('.', '', $now[0]);
4305 * Extract urls from a piece of text
4307 * @return array of urls found in $string
4309 function getUrls($string)
4311 $lines = explode("<br>", trim($string));
4313 foreach($lines as $line){
4314 $regex = '/http?\:\/\/[^\" ]+/i';
4315 preg_match_all($regex, $line, $matches);
4316 foreach($matches[0] as $match){
4325 * Sanitize image file from hostile content
4326 * @param string $path Image file
4327 * @param bool $jpeg Accept only JPEGs?
4329 function verify_image_file($path, $jpeg = false)
4331 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4332 $img = imagecreatefromstring(file_get_contents($path));
4336 $img_size = getimagesize($path);
4337 $filetype = $img_size['mime'];
4338 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4339 if($filetype == "image/jpeg" || $jpeg) {
4342 $image = ob_get_clean();
4343 // not writing directly because imagejpeg does not work with streams
4344 if(file_put_contents($path, $image)) {
4347 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4348 imagealphablending($img, true);
4349 imagesavealpha($img, true);
4352 $image = ob_get_clean();
4353 if(file_put_contents($path, $image)) {
4360 // check image manually
4361 $fp = fopen($path, "r");
4362 if(!$fp) return false;
4363 $data = fread($fp, 4096);
4365 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",
4367 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4376 * Verify uploaded image
4377 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4378 * @param string $path Image path
4379 * @param bool $jpeg_only Accept only JPEGs?
4381 function verify_uploaded_image($path, $jpeg_only = false)
4383 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4385 $supportedExtensions['png'] = 'image/png';
4388 if(!file_exists($path) || !is_file($path)) {
4392 $img_size = getimagesize($path);
4393 $filetype = $img_size['mime'];
4394 $ext = end(explode(".", $path));
4395 if(substr_count('..', $path) > 0 || $ext === $path || !in_array(strtolower($ext), array_keys($supportedExtensions)) ||
4396 !in_array($filetype, array_values($supportedExtensions))) {
4399 return verify_image_file($path, $jpeg_only);
4402 function cmp_beans($a, $b)
4404 global $sugar_web_service_order_by;
4405 //If the order_by field is not valid, return 0;
4406 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4409 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4410 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4414 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4422 function order_beans($beans, $field_name)
4424 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4425 global $sugar_web_service_order_by;
4426 $sugar_web_service_order_by = $field_name;
4427 usort($beans, "cmp_beans");
4431 //check to see if custom utils exists
4432 if(file_exists('custom/include/custom_utils.php')){
4433 include_once('custom/include/custom_utils.php');
4436 //check to see if custom utils exists in Extension framework
4437 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4438 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4441 * @param $input - the input string to sanitize
4442 * @param int $quotes - use quotes
4443 * @param string $charset - the default charset
4444 * @param bool $remove - strip tags or not
4445 * @return string - the sanitized string
4447 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4449 return htmlentities($input, $quotes, $charset);
4454 * get_language_header
4456 * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
4457 * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
4459 * @return String The lang=[Current Language] markup to insert into the <html> tag
4461 function get_language_header()
4463 return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";