PageRenderTime 92ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/include/utils.php

https://github.com/AUTOPLANNING/SuiteCRM
PHP | 5365 lines | 3664 code | 616 blank | 1085 comment | 793 complexity | a66930d1e9f4fbcefc534aa3d1972608 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /*
  3. *
  4. * SugarCRM Community Edition is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
  6. *
  7. * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
  8. * Copyright (C) 2011 - 2016 SalesAgility Ltd.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it under
  11. * the terms of the GNU Affero General Public License version 3 as published by the
  12. * Free Software Foundation with the addition of the following permission added
  13. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  14. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  15. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  16. *
  17. * This program is distributed in the hope that it will be useful, but WITHOUT
  18. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  19. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  20. * details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License along with
  23. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  24. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  25. * 02110-1301 USA.
  26. *
  27. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  28. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  29. *
  30. * The interactive user interfaces in modified source and object code versions
  31. * of this program must display Appropriate Legal Notices, as required under
  32. * Section 5 of the GNU Affero General Public License version 3.
  33. *
  34. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  35. * these Appropriate Legal Notices must retain the display of the "Powered by
  36. * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
  37. * reasonably feasible for technical reasons, the Appropriate Legal Notices must
  38. * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
  39. */
  40. /*********************************************************************************
  41. * Description: Includes generic helper functions used throughout the application.
  42. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  43. * All Rights Reserved.
  44. * Contributor(s): ______________________________________..
  45. ********************************************************************************/
  46. require_once 'include/SugarObjects/SugarConfig.php';
  47. require_once 'include/utils/security_utils.php';
  48. function make_sugar_config(&$sugar_config)
  49. {
  50. /* used to convert non-array config.php file to array format */
  51. global $admin_export_only;
  52. global $cache_dir;
  53. global $calculate_response_time;
  54. global $create_default_user;
  55. global $dateFormats;
  56. global $dbconfig;
  57. global $dbconfigoption;
  58. global $default_action;
  59. global $default_charset;
  60. global $default_currency_name;
  61. global $default_currency_symbol;
  62. global $default_currency_iso4217;
  63. global $defaultDateFormat;
  64. global $default_language;
  65. global $default_module;
  66. global $default_password;
  67. global $default_theme;
  68. global $defaultTimeFormat;
  69. global $default_user_is_admin;
  70. global $default_user_name;
  71. global $disable_export;
  72. global $disable_persistent_connections;
  73. global $display_email_template_variable_chooser;
  74. global $display_inbound_email_buttons;
  75. global $history_max_viewed;
  76. global $host_name;
  77. global $import_dir;
  78. global $languages;
  79. global $list_max_entries_per_page;
  80. global $lock_default_user_name;
  81. global $log_memory_usage;
  82. global $nameFormats;
  83. global $requireAccounts;
  84. global $RSS_CACHE_TIME;
  85. global $session_dir;
  86. global $site_URL;
  87. global $site_url;
  88. global $sugar_version;
  89. global $timeFormats;
  90. global $tmp_dir;
  91. global $translation_string_prefix;
  92. global $unique_key;
  93. global $upload_badext;
  94. global $upload_dir;
  95. global $upload_maxsize;
  96. global $import_max_execution_time;
  97. global $list_max_entries_per_subpanel;
  98. global $passwordsetting;
  99. // assumes the following variables must be set:
  100. // $dbconfig, $dbconfigoption, $cache_dir, $session_dir, $site_URL, $upload_dir
  101. $sugar_config = array(
  102. 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
  103. 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
  104. 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
  105. 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
  106. 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
  107. 'chartEngine' => 'Jit',
  108. 'date_formats' => empty($dateFormats) ? array(
  109. 'Y-m-d' => '2010-12-23',
  110. 'd-m-Y' => '23-12-2010',
  111. 'm-d-Y' => '12-23-2010',
  112. 'Y/m/d' => '2010/12/23',
  113. 'd/m/Y' => '23/12/2010',
  114. 'm/d/Y' => '12/23/2010',
  115. 'Y.m.d' => '2010.12.23',
  116. 'd.m.Y' => '23.12.2010',
  117. 'm.d.Y' => '12.23.2010',
  118. ) : $dateFormats,
  119. 'dbconfig' => $dbconfig, // this must be set!!
  120. 'dbconfigoption' => $dbconfigoption, // this must be set!!
  121. 'default_action' => empty($default_action) ? 'index' : $default_action,
  122. 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
  123. 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
  124. 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
  125. 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
  126. 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
  127. 'default_locale_name_format' => empty($defaultNameFormat) ? 's f l' : $defaultNameFormat,
  128. 'default_export_charset' => 'UTF-8',
  129. 'default_language' => empty($default_language) ? 'en_us' : $default_language,
  130. 'default_module' => empty($default_module) ? 'Home' : $default_module,
  131. 'default_password' => empty($default_password) ? '' : $default_password,
  132. 'default_permissions' => array(
  133. 'dir_mode' => 02770,
  134. 'file_mode' => 0755,
  135. 'chown' => '',
  136. 'chgrp' => '',
  137. ),
  138. 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
  139. 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
  140. 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
  141. 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
  142. 'disable_export' => empty($disable_export) ? false : $disable_export,
  143. 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
  144. 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
  145. 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
  146. 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
  147. 'host_name' => empty($host_name) ? 'localhost' : $host_name,
  148. 'import_dir' => $import_dir, // this must be set!!
  149. 'import_max_records_per_file' => 100,
  150. 'import_max_records_total_limit' => '',
  151. 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
  152. 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
  153. 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
  154. 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
  155. 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
  156. 'name_formats' => empty($nameFormats) ? array(
  157. 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
  158. 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s',
  159. ) : $nameFormats,
  160. 'portal_view' => 'single_user',
  161. 'resource_management' => array(
  162. 'special_query_limit' => 50000,
  163. 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
  164. 'default_limit' => 1000,
  165. ),
  166. 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
  167. 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
  168. 'session_dir' => $session_dir, // this must be set!!
  169. 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
  170. 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
  171. 'showThemePicker' => true,
  172. 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
  173. 'time_formats' => empty($timeFormats) ? array(
  174. 'H:i' => '23:00', 'h:ia' => '11:00 pm', 'h:iA' => '11:00PM',
  175. 'H.i' => '23.00', 'h.ia' => '11.00 pm', 'h.iA' => '11.00PM', ) : $timeFormats,
  176. 'tmp_dir' => $tmp_dir, // this must be set!!
  177. 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
  178. 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
  179. 'upload_badext' => empty($upload_badext) ? array(
  180. 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
  181. 'asp', 'cfm', 'js', 'vbs', 'html', 'htm', ) : $upload_badext,
  182. 'upload_dir' => $upload_dir, // this must be set!!
  183. 'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
  184. 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
  185. 'lock_homepage' => false,
  186. 'lock_subpanels' => false,
  187. 'max_dashlets_homepage' => 15,
  188. 'dashlet_display_row_options' => array('1', '3', '5', '10'),
  189. 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
  190. 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
  191. 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
  192. 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
  193. 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
  194. 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
  195. 'default_call_status' => 'Planned',
  196. 'js_lang_version' => 1,
  197. 'passwordsetting' => empty($passwordsetting) ? array(
  198. 'SystemGeneratedPasswordON' => '',
  199. 'generatepasswordtmpl' => '',
  200. 'lostpasswordtmpl' => '',
  201. 'forgotpasswordON' => true,
  202. 'linkexpiration' => '1',
  203. 'linkexpirationtime' => '30',
  204. 'linkexpirationtype' => '1',
  205. 'systexpiration' => '0',
  206. 'systexpirationtime' => '',
  207. 'systexpirationtype' => '0',
  208. 'systexpirationlogin' => '',
  209. ) : $passwordsetting,
  210. 'use_sprites' => function_exists('imagecreatetruecolor'),
  211. 'search_wildcard_infront' => false,
  212. 'search_wildcard_char' => '%',
  213. 'jobs' => array(
  214. 'min_retry_interval' => 60, // minimal job retry delay
  215. 'max_retries' => 5, // how many times to retry the job
  216. 'timeout' => 86400, // how long a job may spend as running before being force-failed
  217. 'soft_lifetime' => 7, // how many days until job record will be soft deleted after completion
  218. 'hard_lifetime' => 21, // how many days until job record will be purged from DB
  219. ),
  220. 'cron' => array(
  221. 'max_cron_jobs' => 10, // max jobs per cron schedule run
  222. 'max_cron_runtime' => 60, // max runtime for cron jobs
  223. 'min_cron_interval' => 30, // minimal interval between cron jobs
  224. ),
  225. );
  226. }
  227. function get_sugar_config_defaults()
  228. {
  229. global $locale;
  230. /*
  231. * used for getting base values for array style config.php. used by the
  232. * installer and to fill in new entries on upgrades. see also:
  233. * sugar_config_union
  234. */
  235. $sugar_config_defaults = array(
  236. 'admin_export_only' => false,
  237. 'export_delimiter' => ',',
  238. 'export_excel_compatible' => false,
  239. 'cache_dir' => 'cache/',
  240. 'calculate_response_time' => true,
  241. 'create_default_user' => false,
  242. 'chartEngine' => 'Jit',
  243. 'date_formats' => array(
  244. 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
  245. 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
  246. 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010', ),
  247. 'name_formats' => array(
  248. 's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
  249. 'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s',
  250. ),
  251. 'dbconfigoption' => array(
  252. 'persistent' => true,
  253. 'autofree' => false,
  254. 'debug' => 0,
  255. 'ssl' => false, ),
  256. 'default_action' => 'index',
  257. 'default_charset' => return_session_value_or_default('default_charset',
  258. 'UTF-8'),
  259. 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
  260. 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
  261. 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
  262. 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
  263. 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
  264. 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
  265. 'default_date_format' => 'm/d/Y',
  266. 'default_locale_name_format' => 's f l',
  267. 'default_export_charset' => 'UTF-8',
  268. 'default_language' => return_session_value_or_default('default_language',
  269. 'en_us'),
  270. 'default_module' => 'Home',
  271. 'default_password' => '',
  272. 'default_permissions' => array(
  273. 'dir_mode' => 02770,
  274. 'file_mode' => 0755,
  275. 'user' => '',
  276. 'group' => '',
  277. ),
  278. 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
  279. 'default_time_format' => 'h:ia',
  280. 'default_user_is_admin' => false,
  281. 'default_user_name' => '',
  282. 'disable_export' => false,
  283. 'disable_persistent_connections' => return_session_value_or_default('disable_persistent_connections',
  284. 'false'),
  285. 'display_email_template_variable_chooser' => false,
  286. 'display_inbound_email_buttons' => false,
  287. 'dump_slow_queries' => false,
  288. 'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
  289. 'email_default_editor' => 'html',
  290. 'email_default_client' => 'sugar',
  291. 'email_default_delete_attachments' => true,
  292. 'history_max_viewed' => 50,
  293. 'installer_locked' => true,
  294. 'import_max_records_per_file' => 100,
  295. 'import_max_records_total_limit' => '',
  296. 'languages' => array('en_us' => 'English (US)'),
  297. 'large_scale_test' => false,
  298. 'list_max_entries_per_page' => 20,
  299. 'list_max_entries_per_subpanel' => 10,
  300. 'lock_default_user_name' => false,
  301. 'log_memory_usage' => false,
  302. 'portal_view' => 'single_user',
  303. 'resource_management' => array(
  304. 'special_query_limit' => 50000,
  305. 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
  306. 'default_limit' => 1000,
  307. ),
  308. 'require_accounts' => true,
  309. 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
  310. '10800'),
  311. 'save_query' => 'all',
  312. 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
  313. 'showThemePicker' => true,
  314. 'slow_query_time_msec' => '100',
  315. 'sugarbeet' => true,
  316. 'time_formats' => array(
  317. 'H:i' => '23:00', 'h:ia' => '11:00pm', 'h:iA' => '11:00PM', 'h:i a' => '11:00 pm', 'h:i A' => '11:00 PM',
  318. 'H.i' => '23.00', 'h.ia' => '11.00pm', 'h.iA' => '11.00PM', 'h.i a' => '11.00 pm', 'h.i A' => '11.00 PM', ),
  319. 'tracker_max_display_length' => 15,
  320. 'translation_string_prefix' => return_session_value_or_default('translation_string_prefix', false),
  321. 'upload_badext' => array(
  322. 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
  323. 'asp', 'cfm', 'js', 'vbs', 'html', 'htm', 'phtml', ),
  324. 'upload_maxsize' => 30000000,
  325. 'import_max_execution_time' => 3600,
  326. // 'use_php_code_json' => returnPhpJsonStatus(),
  327. 'verify_client_ip' => true,
  328. 'js_custom_version' => '',
  329. 'js_lang_version' => 1,
  330. 'lead_conv_activity_opt' => 'donothing',
  331. 'lock_homepage' => false,
  332. 'lock_subpanels' => false,
  333. 'max_dashlets_homepage' => '15',
  334. 'default_max_tabs' => '7',
  335. 'dashlet_display_row_options' => array('1', '3', '5', '10'),
  336. 'default_subpanel_tabs' => true,
  337. 'default_subpanel_links' => false,
  338. 'default_swap_last_viewed' => false,
  339. 'default_swap_shortcuts' => false,
  340. 'default_navigation_paradigm' => 'gm',
  341. 'admin_access_control' => false,
  342. 'use_common_ml_dir' => false,
  343. 'common_ml_dir' => '',
  344. 'vcal_time' => '2',
  345. 'calendar' => array(
  346. 'default_view' => 'week',
  347. 'show_calls_by_default' => true,
  348. 'show_tasks_by_default' => true,
  349. 'show_completed_by_default' => true,
  350. 'editview_width' => 990,
  351. 'editview_height' => 485,
  352. 'day_timestep' => 15,
  353. 'week_timestep' => 30,
  354. 'items_draggable' => true,
  355. 'items_resizable' => true,
  356. 'enable_repeat' => true,
  357. 'max_repeat_count' => 1000,
  358. ),
  359. 'passwordsetting' => empty($passwordsetting) ? array(
  360. 'SystemGeneratedPasswordON' => '',
  361. 'generatepasswordtmpl' => '',
  362. 'lostpasswordtmpl' => '',
  363. 'forgotpasswordON' => false,
  364. 'linkexpiration' => '1',
  365. 'linkexpirationtime' => '30',
  366. 'linkexpirationtype' => '1',
  367. 'systexpiration' => '0',
  368. 'systexpirationtime' => '',
  369. 'systexpirationtype' => '0',
  370. 'systexpirationlogin' => '',
  371. ) : $passwordsetting,
  372. 'use_real_names' => true,
  373. 'search_wildcard_infront' => false,
  374. 'search_wildcard_char' => '%',
  375. 'jobs' => array(
  376. 'min_retry_interval' => 30, // 30 seconds minimal job retry
  377. 'max_retries' => 5, // how many times to retry the job
  378. 'timeout' => 86400, // how long a job may spend as running before being force-failed
  379. ),
  380. 'cron' => array(
  381. 'max_cron_jobs' => 10, // max jobs per cron schedule run
  382. 'max_cron_runtime' => 30, // max runtime for cron jobs
  383. 'min_cron_interval' => 30, // minimal interval between cron jobs
  384. ),
  385. );
  386. if (!is_object($locale)) {
  387. $locale = new Localization();
  388. }
  389. $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
  390. $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
  391. return $sugar_config_defaults;
  392. }
  393. /**
  394. * @deprecated use SugarView::getMenu() instead
  395. */
  396. function load_menu($path)
  397. {
  398. global $module_menu;
  399. if (file_exists($path.'Menu.php')) {
  400. require $path.'Menu.php';
  401. }
  402. if (file_exists('custom/'.$path.'Ext/Menus/menu.ext.php')) {
  403. require 'custom/'.$path.'Ext/Menus/menu.ext.php';
  404. }
  405. if (file_exists('custom/application/Ext/Menus/menu.ext.php')) {
  406. require 'custom/application/Ext/Menus/menu.ext.php';
  407. }
  408. return $module_menu;
  409. }
  410. /**
  411. * get_notify_template_file
  412. * This function will return the location of the email notifications template to use.
  413. *
  414. * @return string relative file path to email notifications template file
  415. */
  416. function get_notify_template_file($language)
  417. {
  418. /*
  419. * Order of operation:
  420. * 1) custom version of specified language
  421. * 2) stock version of specified language
  422. * 3) custom version of en_us template
  423. * 4) stock en_us template
  424. */
  425. // set $file to the base code template so it's set if none of the conditions pass
  426. $file = 'include/language/en_us.notify_template.html';
  427. if (file_exists("custom/include/language/{$language}.notify_template.html")) {
  428. $file = "custom/include/language/{$language}.notify_template.html";
  429. } elseif (file_exists("include/language/{$language}.notify_template.html")) {
  430. $file = "include/language/{$language}.notify_template.html";
  431. } elseif (file_exists('custom/include/language/en_us.notify_template.html')) {
  432. $file = 'custom/include/language/en_us.notify_template.html';
  433. }
  434. return $file;
  435. }
  436. function sugar_config_union($default, $override)
  437. {
  438. // a little different then array_merge and array_merge_recursive. we want
  439. // the second array to override the first array if the same value exists,
  440. // otherwise merge the unique keys. it handles arrays of arrays recursively
  441. // might be suitable for a generic array_union
  442. if (!is_array($override)) {
  443. $override = array();
  444. }
  445. foreach ($default as $key => $value) {
  446. if (!array_key_exists($key, $override)) {
  447. $override[$key] = $value;
  448. } elseif (is_array($key)) {
  449. $override[$key] = sugar_config_union($value, $override[$key]);
  450. }
  451. }
  452. return $override;
  453. }
  454. function make_not_writable($file)
  455. {
  456. // Returns true if the given file/dir has been made not writable
  457. $ret_val = false;
  458. if (is_file($file) || is_dir($file)) {
  459. if (!is_writable($file)) {
  460. $ret_val = true;
  461. } else {
  462. $original_fileperms = fileperms($file);
  463. // take away writable permissions
  464. $new_fileperms = $original_fileperms & ~0x0092;
  465. @sugar_chmod($file, $new_fileperms);
  466. if (!is_writable($file)) {
  467. $ret_val = true;
  468. }
  469. }
  470. }
  471. return $ret_val;
  472. }
  473. /** This function returns the name of the person.
  474. * It currently returns "first last". It should not put the space if either name is not available.
  475. * It should not return errors if either name is not available.
  476. * If no names are present, it will return ""
  477. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  478. * All Rights Reserved.
  479. * Contributor(s): ______________________________________..
  480. */
  481. function return_name($row, $first_column, $last_column)
  482. {
  483. $first_name = '';
  484. $last_name = '';
  485. $full_name = '';
  486. if (isset($row[$first_column])) {
  487. $first_name = stripslashes($row[$first_column]);
  488. }
  489. if (isset($row[$last_column])) {
  490. $last_name = stripslashes($row[$last_column]);
  491. }
  492. $full_name = $first_name;
  493. // If we have a first name and we have a last name
  494. if ($full_name != '' && $last_name != '') {
  495. // append a space, then the last name
  496. $full_name .= ' '.$last_name;
  497. } // If we have no first name, but we have a last name
  498. elseif ($last_name != '') {
  499. // append the last name without the space.
  500. $full_name .= $last_name;
  501. }
  502. return $full_name;
  503. }
  504. function get_languages()
  505. {
  506. global $sugar_config;
  507. $lang = $sugar_config['languages'];
  508. if (!empty($sugar_config['disabled_languages'])) {
  509. foreach (explode(',', $sugar_config['disabled_languages']) as $disable) {
  510. unset($lang[$disable]);
  511. }
  512. }
  513. return $lang;
  514. }
  515. function get_all_languages()
  516. {
  517. global $sugar_config;
  518. return $sugar_config['languages'];
  519. }
  520. function get_language_display($key)
  521. {
  522. global $sugar_config;
  523. return $sugar_config['languages'][$key];
  524. }
  525. function get_assigned_user_name($assigned_user_id, $is_group = '')
  526. {
  527. static $saved_user_list = null;
  528. if (empty($saved_user_list)) {
  529. $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
  530. }
  531. if (isset($saved_user_list[$assigned_user_id])) {
  532. return $saved_user_list[$assigned_user_id];
  533. }
  534. return '';
  535. }
  536. /**
  537. * retrieves the user_name column value (login).
  538. *
  539. * @param string id GUID of user
  540. *
  541. * @return string
  542. */
  543. function get_user_name($id)
  544. {
  545. global $db;
  546. if (empty($db)) {
  547. $db = DBManagerFactory::getInstance();
  548. }
  549. $q = "SELECT user_name FROM users WHERE id='{$id}'";
  550. $r = $db->query($q);
  551. $a = $db->fetchByAssoc($r);
  552. return (empty($a)) ? '' : $a['user_name'];
  553. }
  554. //TODO Update to use global cache
  555. /**
  556. * get_user_array.
  557. *
  558. * This is a helper function to return an Array of users depending on the parameters passed into the function.
  559. * This function uses the get_register_value function by default to use a caching layer where supported.
  560. * This function has been updated return the array sorted by user preference of name display (bug 62712)
  561. *
  562. * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
  563. * @param string $status String value indicating the status to filter users by, "Active" by default
  564. * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
  565. * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
  566. * @param string $user_name_filter String value indicating the user_name filter (searches the user_name column of users table) to optionally search with, blank by default
  567. * @param string $portal_filter String query filter for portal users (defaults to searching non-portal users), change to blank if you wish to search for all users including portal users
  568. * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
  569. *
  570. * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
  571. */
  572. function get_user_array($add_blank = true, $status = 'Active', $user_id = '', $use_real_name = false, $user_name_filter = '', $portal_filter = ' AND portal_only=0 ', $from_cache = true)
  573. {
  574. global $locale, $sugar_config, $current_user;
  575. if (empty($locale)) {
  576. $locale = new Localization();
  577. }
  578. if ($from_cache) {
  579. $key_name = $add_blank.$status.$user_id.$use_real_name.$user_name_filter.$portal_filter;
  580. $user_array = get_register_value('user_array', $key_name);
  581. }
  582. if (empty($user_array)) {
  583. $db = DBManagerFactory::getInstance();
  584. $temp_result = array();
  585. // Including deleted users for now.
  586. if (empty($status)) {
  587. $query = 'SELECT id, first_name, last_name, user_name FROM users WHERE 1=1'.$portal_filter;
  588. } else {
  589. $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
  590. }
  591. /* BEGIN - SECURITY GROUPS */
  592. global $current_user, $sugar_config;
  593. if (!is_admin($current_user)
  594. && isset($sugar_config['securitysuite_filter_user_list'])
  595. && $sugar_config['securitysuite_filter_user_list'] == true
  596. && (empty($_REQUEST['module']) || $_REQUEST['module'] != 'Home')
  597. && (empty($_REQUEST['action']) || $_REQUEST['action'] != 'DynamicAction')
  598. ) {
  599. require_once 'modules/SecurityGroups/SecurityGroup.php';
  600. global $current_user;
  601. $group_where = SecurityGroup::getGroupUsersWhere($current_user->id);
  602. $query .= ' AND ('.$group_where.') ';
  603. }
  604. /* END - SECURITY GROUPS */
  605. if (!empty($user_name_filter)) {
  606. $user_name_filter = $db->quote($user_name_filter);
  607. $query .= " AND user_name LIKE '$user_name_filter%' ";
  608. }
  609. if (!empty($user_id)) {
  610. $query .= " OR id='{$user_id}'";
  611. }
  612. //get the user preference for name formatting, to be used in order by
  613. $order_by_string = ' user_name ASC ';
  614. if (!empty($current_user) && !empty($current_user->id)) {
  615. $formatString = $current_user->getPreference('default_locale_name_format');
  616. //create the order by string based on position of first and last name in format string
  617. $order_by_string = ' user_name ASC ';
  618. $firstNamePos = strpos($formatString, 'f');
  619. $lastNamePos = strpos($formatString, 'l');
  620. if ($firstNamePos !== false || $lastNamePos !== false) {
  621. //its possible for first name to be skipped, check for this
  622. if ($firstNamePos === false) {
  623. $order_by_string = 'last_name ASC';
  624. } else {
  625. $order_by_string = ($lastNamePos < $firstNamePos) ? 'last_name, first_name ASC' : 'first_name, last_name ASC';
  626. }
  627. }
  628. }
  629. $query = $query.' ORDER BY '.$order_by_string;
  630. $GLOBALS['log']->debug("get_user_array query: $query");
  631. $result = $db->query($query, true, 'Error filling in user array: ');
  632. if ($add_blank == true) {
  633. // Add in a blank row
  634. $temp_result[''] = '';
  635. }
  636. // Get the id and the name.
  637. while ($row = $db->fetchByAssoc($result)) {
  638. if ($use_real_name == true || showFullName()) {
  639. if (isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
  640. $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']);
  641. } else {
  642. $temp_result[$row['id']] = $row['user_name'];
  643. }
  644. } else {
  645. $temp_result[$row['id']] = $row['user_name'];
  646. }
  647. }
  648. $user_array = $temp_result;
  649. if ($from_cache) {
  650. set_register_value('user_array', $key_name, $temp_result);
  651. }
  652. }
  653. return $user_array;
  654. }
  655. /**
  656. * uses a different query to return a list of users than get_user_array()
  657. * Used from QuickSearch.php.
  658. *
  659. * @param args string where clause entry
  660. *
  661. * @return array Array of Users' details that match passed criteria
  662. */
  663. function getUserArrayFromFullName($args, $hide_portal_users = false)
  664. {
  665. global $locale;
  666. $db = DBManagerFactory::getInstance();
  667. // jmorais@dri - Bug #51411
  668. //
  669. // Refactor the code responsible for parsing supplied $args, this way we
  670. // ensure that if $args has at least one space (after trim), the $inClause
  671. // will be composed by several clauses ($inClauses) inside parenthesis.
  672. //
  673. // Ensuring that operator precedence is respected, and avoiding
  674. // inactive/deleted users to be retrieved.
  675. //
  676. $args = trim($args);
  677. if (strpos($args, ' ')) {
  678. $inClauses = array();
  679. $argArray = explode(' ', $args);
  680. foreach ($argArray as $arg) {
  681. $arg = $db->quote($arg);
  682. $inClauses[] = "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
  683. }
  684. $inClause = '('.implode('OR ', $inClauses).')';
  685. } else {
  686. $args = $db->quote($args);
  687. $inClause = "(first_name LIKE '{$args}%' OR last_name LIKE '{$args}%')";
  688. }
  689. // ~jmorais@dri
  690. $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
  691. if ($hide_portal_users) {
  692. $query .= ' portal_only=0 AND ';
  693. }
  694. $query .= $inClause;
  695. /* BEGIN - SECURITY GROUPS */
  696. global $current_user, $sugar_config;
  697. if (!is_admin($current_user)
  698. && isset($sugar_config['securitysuite_filter_user_list'])
  699. && $sugar_config['securitysuite_filter_user_list'] == true
  700. ) {
  701. require_once 'modules/SecurityGroups/SecurityGroup.php';
  702. global $current_user;
  703. $group_where = SecurityGroup::getGroupUsersWhere($current_user->id);
  704. $query .= ' AND ('.$group_where.') ';
  705. }
  706. /* END - SECURITY GROUPS */
  707. $query .= ' ORDER BY last_name ASC';
  708. $r = $db->query($query);
  709. $ret = array();
  710. while ($a = $db->fetchByAssoc($r)) {
  711. $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
  712. }
  713. return $ret;
  714. }
  715. /**
  716. * based on user pref then system pref.
  717. */
  718. function showFullName()
  719. {
  720. global $sugar_config;
  721. global $current_user;
  722. static $showFullName = null;
  723. if (is_null($showFullName)) {
  724. $sysPref = !empty($sugar_config['use_real_names']);
  725. $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
  726. if ($userPref != null) {
  727. $showFullName = ($userPref == 'on');
  728. } else {
  729. $showFullName = $sysPref;
  730. }
  731. }
  732. return $showFullName;
  733. }
  734. function clean($string, $maxLength)
  735. {
  736. $string = substr($string, 0, $maxLength);
  737. return escapeshellcmd($string);
  738. }
  739. /**
  740. * Copy the specified request variable to the member variable of the specified object.
  741. * Do no copy if the member variable is already set.
  742. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  743. * All Rights Reserved.
  744. * Contributor(s): ______________________________________..
  745. */
  746. function safe_map($request_var, &$focus, $always_copy = false)
  747. {
  748. safe_map_named($request_var, $focus, $request_var, $always_copy);
  749. }
  750. /**
  751. * Copy the specified request variable to the member variable of the specified object.
  752. * Do no copy if the member variable is already set.
  753. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  754. * All Rights Reserved.
  755. * Contributor(s): ______________________________________..
  756. */
  757. function safe_map_named($request_var, &$focus, $member_var, $always_copy)
  758. {
  759. if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
  760. $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
  761. $focus->$member_var = $_REQUEST[$request_var];
  762. }
  763. }
  764. /**
  765. * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
  766. *
  767. * @param string $language specific language to load
  768. *
  769. * @return array lang strings
  770. */
  771. function return_app_list_strings_language($language)
  772. {
  773. global $app_list_strings;
  774. global $sugar_config;
  775. $cache_key = 'app_list_strings.'.$language;
  776. // Check for cached value
  777. $cache_entry = sugar_cache_retrieve($cache_key);
  778. if (!empty($cache_entry)) {
  779. return $cache_entry;
  780. }
  781. $default_language = isset($sugar_config['default_language']) ? $sugar_config['default_language'] : 'en_us';
  782. $temp_app_list_strings = $app_list_strings;
  783. $langs = array();
  784. if ($language != 'en_us') {
  785. $langs[] = 'en_us';
  786. }
  787. if ($default_language != 'en_us' && $language != $default_language) {
  788. $langs[] = $default_language;
  789. }
  790. $langs[] = $language;
  791. $app_list_strings_array = array();
  792. foreach ($langs as $lang) {
  793. $app_list_strings = array();
  794. if (file_exists("include/language/$lang.lang.php")) {
  795. include "include/language/$lang.lang.php";
  796. $GLOBALS['log']->info("Found language file: $lang.lang.php");
  797. }
  798. if (file_exists("include/language/$lang.lang.override.php")) {
  799. include "include/language/$lang.lang.override.php";
  800. $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
  801. }
  802. if (file_exists("include/language/$lang.lang.php.override")) {
  803. include "include/language/$lang.lang.php.override";
  804. $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
  805. }
  806. $app_list_strings_array[] = $app_list_strings;
  807. }
  808. $app_list_strings = array();
  809. foreach ($app_list_strings_array as $app_list_strings_item) {
  810. $app_list_strings = sugarLangArrayMerge($app_list_strings, $app_list_strings_item);
  811. }
  812. foreach ($langs as $lang) {
  813. if (file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
  814. $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php", $app_list_strings);
  815. $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
  816. }
  817. if (file_exists("custom/include/language/$lang.lang.php")) {
  818. include "custom/include/language/$lang.lang.php";
  819. $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
  820. }
  821. }
  822. if (!isset($app_list_strings)) {
  823. $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");
  824. return;
  825. }
  826. $return_value = $app_list_strings;
  827. $app_list_strings = $temp_app_list_strings;
  828. sugar_cache_put($cache_key, $return_value);
  829. return $return_value;
  830. }
  831. /**
  832. * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
  833. * $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.
  834. *
  835. * @param file string the language that you want include,
  836. * @param app_list_strings array the golbal strings
  837. *
  838. * @return array
  839. */
  840. //jchi 25347
  841. function _mergeCustomAppListStrings($file, $app_list_strings)
  842. {
  843. $app_list_strings_original = $app_list_strings;
  844. unset($app_list_strings);
  845. // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
  846. // This way, language file can add items to save specific standard codelist from being overwritten
  847. $exemptDropdowns = array();
  848. include $file;
  849. if (!isset($app_list_strings) || !is_array($app_list_strings)) {
  850. return $app_list_strings_original;
  851. }
  852. //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
  853. // FG - bug 45525 - Specific codelists must NOT be overwritten
  854. $exemptDropdowns[] = 'moduleList';
  855. $exemptDropdowns[] = 'moduleListSingular';
  856. $exemptDropdowns = array_merge($exemptDropdowns, getTypeDisplayList());
  857. foreach ($app_list_strings as $key => $value) {
  858. if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original)) {
  859. unset($app_list_strings_original["$key"]);
  860. }
  861. }
  862. $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original, $app_list_strings);
  863. return $app_list_strings;
  864. }
  865. /**
  866. * This function retrieves an application language file and returns the array of strings included.
  867. *
  868. * @param string $language specific language to load
  869. *
  870. * @return array lang strings
  871. */
  872. function return_application_language($language)
  873. {
  874. global $app_strings, $sugar_config;
  875. $cache_key = 'app_strings.'.$language;
  876. // Check for cached value
  877. $cache_entry = sugar_cache_retrieve($cache_key);
  878. if (!empty($cache_entry)) {
  879. return $cache_entry;
  880. }
  881. $temp_app_strings = $app_strings;
  882. $default_language = $sugar_config['default_language'];
  883. $langs = array();
  884. if ($language != 'en_us') {
  885. $langs[] = 'en_us';
  886. }
  887. if ($default_language != 'en_us' && $language != $default_language) {
  888. $langs[] = $default_language;
  889. }
  890. $langs[] = $language;
  891. $app_strings_array = array();
  892. foreach ($langs as $lang) {
  893. $app_strings = array();
  894. if (file_exists("include/language/$lang.lang.php")) {
  895. include "include/language/$lang.lang.php";
  896. $GLOBALS['log']->info("Found language file: $lang.lang.php");
  897. }
  898. if (file_exists("include/language/$lang.lang.override.php")) {
  899. include "include/language/$lang.lang.override.php";
  900. $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
  901. }
  902. if (file_exists("include/language/$lang.lang.php.override")) {
  903. include "include/language/$lang.lang.php.override";
  904. $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
  905. }
  906. if (file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
  907. include "custom/application/Ext/Language/$lang.lang.ext.php";
  908. $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
  909. }
  910. if (file_exists("custom/include/language/$lang.lang.php")) {
  911. include "custom/include/language/$lang.lang.php";
  912. $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
  913. }
  914. $app_strings_array[] = $app_strings;
  915. }
  916. $app_strings = array();
  917. foreach ($app_strings_array as $app_strings_item) {
  918. $app_strings = sugarLangArrayMerge($app_strings, $app_strings_item);
  919. }
  920. if (!isset($app_strings)) {
  921. $GLOBALS['log']->fatal('Unable to load the application language strings');
  922. return;
  923. }
  924. // If we are in debug mode for translating, turn on the prefix now!
  925. if (!empty($sugar_config['translation_string_prefix'])) {
  926. foreach ($app_strings as $entry_key => $entry_value) {
  927. $app_strings[$entry_key] = $language.' '.$entry_value;
  928. }
  929. }
  930. if (isset($_SESSION['show_deleted'])) {
  931. $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
  932. $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
  933. $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
  934. $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
  935. }
  936. $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
  937. $return_value = $app_strings;
  938. $app_strings = $temp_app_strings;
  939. sugar_cache_put($cache_key, $return_value);
  940. return $return_value;
  941. }
  942. /**
  943. * This function retrieves a module's language file and returns the array of strings included.
  944. *
  945. * @param string $language specific language to load
  946. * @param string $module module name to load strings for
  947. * @param bool $refresh optional, true if you want to rebuild the language strings
  948. *
  949. * @return array lang strings
  950. */
  951. function return_module_language($language, $module, $refresh = false)
  952. {
  953. global $mod_strings;
  954. global $sugar_config;
  955. global $currentModule;
  956. // Jenny - Bug 8119: Need to check if $module is not empty
  957. if (empty($module)) {
  958. $stack = debug_backtrace();
  959. $GLOBALS['log']->warn('Variable module is not in return_module_language '.var_export($stack, true));
  960. return array();
  961. }
  962. if (!$refresh) {
  963. $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
  964. // Check for cached value
  965. $cache_entry = sugar_cache_retrieve($cache_key);
  966. if (!empty($cache_entry) && is_array($cache_entry)) {
  967. return $cache_entry;
  968. }
  969. }
  970. // Store the current mod strings for later
  971. $temp_mod_strings = $mod_strings;
  972. $loaded_mod_strings = array();
  973. $language_used = $language;
  974. $default_language = $sugar_config['default_language'];
  975. if (empty($language)) {
  976. $language = $default_language;
  977. }
  978. // Bug 21559 - So we can get all the strings defined in the template, refresh
  979. // the vardefs file if the cached language file doesn't exist.
  980. if (!file_exists(sugar_cached('modules/').$module.'/language/'.$language.'.lang.php')
  981. && !empty($GLOBALS['beanList'][$module])
  982. ) {
  983. $object = BeanFactory::getObjectName($module);
  984. VardefManager::refreshVardefs($module, $object);
  985. }
  986. $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language, $refresh);
  987. // cn: bug 6048 - merge en_us with requested language
  988. if ($language != $sugar_config['default_language']) {
  989. $loaded_mod_strings = sugarLangArrayMerge(
  990. LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'], $refresh),
  991. $loaded_mod_strings
  992. );
  993. }
  994. // Load in en_us strings by default
  995. if ($language != 'en_us' && $sugar_config['default_language'] != 'en_us') {
  996. $loaded_mod_strings = sugarLangArrayMerge(
  997. LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
  998. $loaded_mod_strings
  999. );
  1000. }
  1001. // If we are in debug mode for translating, turn on the prefix now!
  1002. if ($sugar_config['translation_string_prefix']) {
  1003. foreach ($loaded_mod_strings as $entry_key => $entry_value) {
  1004. $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
  1005. }
  1006. }
  1007. $return_value = $loaded_mod_strings;
  1008. if (!isset($mod_strings)) {
  1009. $mod_strings = $return_value;
  1010. } else {
  1011. $mod_strings = $temp_mod_strings;
  1012. }
  1013. $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
  1014. sugar_cache_put($cache_key, $return_value);
  1015. return $return_value;
  1016. }
  1017. /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
  1018. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1019. * All Rights Reserved.
  1020. * Contributor(s): ______________________________________..
  1021. * If you are using the current language, do not call this function unless you are loading it for the first time */
  1022. function return_mod_list_strings_language($language, $module)
  1023. {
  1024. global $mod_list_strings;
  1025. global $sugar_config;
  1026. global $currentModule;
  1027. $cache_key = 'mod_list_str_lang.'.$language.$module;
  1028. // Check for cached value
  1029. $cache_entry = sugar_cache_retrieve($cache_key);
  1030. if (!empty($cache_entry)) {
  1031. return $cache_entry;
  1032. }
  1033. $language_used = $language;
  1034. $temp_mod_list_strings = $mod_list_strings;
  1035. $default_language = $sugar_config['default_language'];
  1036. if ($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
  1037. return $mod_list_strings;
  1038. }
  1039. // cn: bug 6351 - include en_us if file langpack not available
  1040. // cn: bug 6048 - merge en_us with requested language
  1041. include "modules/$module/language/en_us.lang.php";
  1042. $en_mod_list_strings = array();
  1043. if ($language_used != $default_language) {
  1044. $en_mod_list_strings = $mod_list_strings;
  1045. }
  1046. if (file_exists("modules/$module/language/$language.lang.php")) {
  1047. include "modules/$module/language/$language.lang.php";
  1048. }
  1049. if (file_exists("modules/$module/language/$language.lang.override.php")) {
  1050. include "modules/$module/language/$language.lang.override.php";
  1051. }
  1052. if (file_exists("modules/$module/language/$language.lang.php.override")) {
  1053. echo 'Please Change:<br>'."modules/$module/language/$language.lang.php.override".'<br>to<br>'.'Please Change:<br>'."modules/$module/language/$language.lang.override.php";
  1054. include "modules/$module/language/$language.lang.php.override";
  1055. }
  1056. // cn: bug 6048 - merge en_us with requested language
  1057. $mod_list_strings = sugarLangArrayMerge($en_mod_list_strings, $mod_list_strings);
  1058. // if we still don't have a language pack, then log an error
  1059. if (!isset($mod_list_strings)) {
  1060. $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})");
  1061. return;
  1062. }
  1063. $return_value = $mod_list_strings;
  1064. $mod_list_strings = $temp_mod_list_strings;
  1065. sugar_cache_put($cache_key, $return_value);
  1066. return $return_value;
  1067. }
  1068. /** This function retrieves a theme's language file and returns the array of strings included.
  1069. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1070. * All Rights Reserved.
  1071. * Contributor(s): ______________________________________..
  1072. */
  1073. function return_theme_language($language, $theme)
  1074. {
  1075. global $mod_strings, $sugar_config, $current_language;
  1076. $language_used = $language;
  1077. $default_language = $sugar_config['default_language'];
  1078. include SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php";
  1079. if (file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")) {
  1080. include SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php";
  1081. }
  1082. if (file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")) {
  1083. 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";
  1084. include SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override";
  1085. }
  1086. if (!isset($theme_strings)) {
  1087. $GLOBALS['log']->warn('Unable to find the theme file for language: '.$language.' and theme: '.$theme);
  1088. require SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php";
  1089. $language_used = $default_language;
  1090. }
  1091. if (!isset($theme_strings)) {
  1092. $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
  1093. return;
  1094. }
  1095. // If we are in debug mode for translating, turn on the prefix now!
  1096. if ($sugar_config['translation_string_prefix']) {
  1097. foreach ($theme_strings as $entry_key => $entry_value) {
  1098. $theme_strings[$entry_key] = $language_used.' '.$entry_value;
  1099. }
  1100. }
  1101. return $theme_strings;
  1102. }
  1103. /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
  1104. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1105. * All Rights Reserved.
  1106. * Contributor(s): ______________________________________..
  1107. */
  1108. function return_session_value_or_default($varname, $default)
  1109. {
  1110. if (isset($_SESSION[$varname]) && $_SESSION[$varname] != '') {
  1111. return $_SESSION[$varname];
  1112. }
  1113. return $default;
  1114. }
  1115. /**
  1116. * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
  1117. * 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.
  1118. *
  1119. * @param &$where_clauses - The array to append the clause to
  1120. * @param $variable_name - The name of the variable to look for an add to the where clause if found
  1121. * @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.
  1122. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1123. * All Rights Reserved.
  1124. * Contributor(s): ______________________________________..
  1125. */
  1126. function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
  1127. {
  1128. if ($SQL_name == null) {
  1129. $SQL_name = $variable_name;
  1130. }
  1131. if (isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != '') {
  1132. array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
  1133. }
  1134. }
  1135. /**
  1136. * Generate the appropriate SQL based on the where clauses.
  1137. *
  1138. * @param $where_clauses - An Array of individual where clauses stored as strings
  1139. * @returns string where_clause - The final SQL where clause to be executed.
  1140. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1141. * All Rights Reserved.
  1142. * Contributor(s): ______________________________________..
  1143. */
  1144. function generate_where_statement($where_clauses)
  1145. {
  1146. $where = '';
  1147. foreach ($where_clauses as $clause) {
  1148. if ($where != '') {
  1149. $where .= ' and ';
  1150. }
  1151. $where .= $clause;
  1152. }
  1153. $GLOBALS['log']->info("Here is the where clause for the list view: $where");
  1154. return $where;
  1155. }
  1156. /**
  1157. * determines if a passed string matches the criteria for a Sugar GUID.
  1158. *
  1159. * @param string $guid
  1160. *
  1161. * @return bool False on failure
  1162. */
  1163. function is_guid($guid)
  1164. {
  1165. if (strlen($guid) != 36) {
  1166. return false;
  1167. }
  1168. if (preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
  1169. return true;
  1170. }
  1171. return true;
  1172. }
  1173. /**
  1174. * A temporary method of generating GUIDs of the correct format for our DB.
  1175. *
  1176. * @return string contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
  1177. *
  1178. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1179. * All Rights Reserved.
  1180. * Contributor(s): ______________________________________..
  1181. */
  1182. function create_guid()
  1183. {
  1184. $microTime = microtime();
  1185. list($a_dec, $a_sec) = explode(' ', $microTime);
  1186. $dec_hex = dechex($a_dec * 1000000);
  1187. $sec_hex = dechex($a_sec);
  1188. ensure_length($dec_hex, 5);
  1189. ensure_length($sec_hex, 6);
  1190. $guid = '';
  1191. $guid .= $dec_hex;
  1192. $guid .= create_guid_section(3);
  1193. $guid .= '-';
  1194. $guid .= create_guid_section(4);
  1195. $guid .= '-';
  1196. $guid .= create_guid_section(4);
  1197. $guid .= '-';
  1198. $guid .= create_guid_section(4);
  1199. $guid .= '-';
  1200. $guid .= $sec_hex;
  1201. $guid .= create_guid_section(6);
  1202. return $guid;
  1203. }
  1204. function create_guid_section($characters)
  1205. {
  1206. $return = '';
  1207. for ($i = 0; $i < $characters; ++$i) {
  1208. $return .= dechex(mt_rand(0, 15));
  1209. }
  1210. return $return;
  1211. }
  1212. function ensure_length(&$string, $length)
  1213. {
  1214. $strlen = strlen($string);
  1215. if ($strlen < $length) {
  1216. $string = str_pad($string, $length, '0');
  1217. } elseif ($strlen > $length) {
  1218. $string = substr($string, 0, $length);
  1219. }
  1220. }
  1221. function microtime_diff($a, $b)
  1222. {
  1223. list($a_dec, $a_sec) = explode(' ', $a);
  1224. list($b_dec, $b_sec) = explode(' ', $b);
  1225. return $b_sec - $a_sec + $b_dec - $a_dec;
  1226. }
  1227. // check if Studio is displayed.
  1228. function displayStudioForCurrentUser()
  1229. {
  1230. global $current_user;
  1231. if ($current_user->isAdmin()) {
  1232. return true;
  1233. }
  1234. return true;
  1235. }
  1236. function displayWorkflowForCurrentUser()
  1237. {
  1238. $_SESSION['display_workflow_for_user'] = false;
  1239. return false;
  1240. }
  1241. // return an array with all modules where the user is an admin.
  1242. function get_admin_modules_for_user($user)
  1243. {
  1244. $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');
  1245. if (!isset($user)) {
  1246. $modules = array();
  1247. return $modules;
  1248. }
  1249. return $user->getDeveloperModules();
  1250. }
  1251. function get_workflow_admin_modules_for_user($user)
  1252. {
  1253. if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
  1254. return $_SESSION['get_workflow_admin_modules_for_user'];
  1255. }
  1256. global $moduleList;
  1257. $workflow_mod_list = array();
  1258. foreach ($moduleList as $module) {
  1259. $workflow_mod_list[$module] = $module;
  1260. }
  1261. // This list is taken from teh previous version of workflow_utils.php
  1262. $workflow_mod_list['Tasks'] = 'Tasks';
  1263. $workflow_mod_list['Calls'] = 'Calls';
  1264. $workflow_mod_list['Meetings'] = 'Meetings';
  1265. $workflow_mod_list['Notes'] = 'Notes';
  1266. $workflow_mod_list['ProjectTask'] = 'Project Tasks';
  1267. $workflow_mod_list['Leads'] = 'Leads';
  1268. $workflow_mod_list['Opportunities'] = 'Opportunities';
  1269. // End of list
  1270. $workflow_admin_modules = array();
  1271. if (empty($user)) {
  1272. return $workflow_admin_modules;
  1273. }
  1274. $actions = ACLAction::getUserActions($user->id);
  1275. //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
  1276. if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess'] == ACL_ALLOW_DEV ||
  1277. $actions['ForecastSchedule']['module']['admin']['aclaccess'] == ACL_ALLOW_ADMIN_DEV)
  1278. ) {
  1279. $workflow_admin_modules['Forecasts'] = 'Forecasts';
  1280. }
  1281. foreach ($workflow_mod_list as $key => $val) {
  1282. if (!in_array($val, $workflow_admin_modules) && ($val != 'iFrames' && $val != 'Feeds' && $val != 'Home' && $val != 'Dashboard'
  1283. && $val != 'Calendar' && $val != 'Activities' && $val != 'Reports') &&
  1284. ($user->isDeveloperForModule($key))
  1285. ) {
  1286. $workflow_admin_modules[$key] = $val;
  1287. }
  1288. }
  1289. $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
  1290. return $workflow_admin_modules;
  1291. }
  1292. // Check if user is admin for at least one module.
  1293. function is_admin_for_any_module($user)
  1294. {
  1295. if (!isset($user)) {
  1296. return false;
  1297. }
  1298. if ($user->isAdmin()) {
  1299. return true;
  1300. }
  1301. return false;
  1302. }
  1303. // Check if user is admin for a specific module.
  1304. function is_admin_for_module($user, $module)
  1305. {
  1306. if (!isset($user)) {
  1307. return false;
  1308. }
  1309. if ($user->isAdmin()) {
  1310. return true;
  1311. }
  1312. return false;
  1313. }
  1314. /**
  1315. * Check if user id belongs to a system admin.
  1316. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1317. * All Rights Reserved.
  1318. * Contributor(s): ______________________________________..
  1319. */
  1320. function is_admin($user)
  1321. {
  1322. if (empty($user)) {
  1323. return false;
  1324. }
  1325. return $user->isAdmin();
  1326. }
  1327. /**
  1328. * Return the display name for a theme if it exists.
  1329. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1330. * All Rights Reserved.
  1331. * Contributor(s): ______________________________________..
  1332. *
  1333. * @deprecated use SugarThemeRegistry::get($theme)->name instead
  1334. */
  1335. function get_theme_display($theme)
  1336. {
  1337. return SugarThemeRegistry::get($theme)->name;
  1338. }
  1339. /**
  1340. * Return an array of directory names.
  1341. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1342. * All Rights Reserved.
  1343. * Contributor(s): ______________________________________..
  1344. *
  1345. * @deprecated use SugarThemeRegistry::availableThemes() instead.
  1346. */
  1347. function get_themes()
  1348. {
  1349. return SugarThemeRegistry::availableThemes();
  1350. }
  1351. /**
  1352. * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
  1353. * Create HTML to display select options in a dropdown list. To be used inside
  1354. * of a select statement in a form.
  1355. * param $option_list - the array of strings to that contains the option list
  1356. * param $selected - the string which contains the default value
  1357. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1358. * All Rights Reserved.
  1359. * Contributor(s): ______________________________________..
  1360. */
  1361. function get_select_options($option_list, $selected)
  1362. {
  1363. return get_select_options_with_id($option_list, $selected);
  1364. }
  1365. /**
  1366. * Create HTML to display select options in a dropdown list. To be used inside
  1367. * 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.
  1368. * param $option_list - the array of strings to that contains the option list
  1369. * param $selected - the string which contains the default value
  1370. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1371. * All Rights Reserved.
  1372. * Contributor(s): ______________________________________..
  1373. */
  1374. function get_select_options_with_id($option_list, $selected_key)
  1375. {
  1376. return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
  1377. }
  1378. /**
  1379. * Create HTML to display select options in a dropdown list. To be used inside
  1380. * 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.
  1381. * param $label_list - the array of strings to that contains the option list
  1382. * param $key_list - the array of strings to that contains the values list
  1383. * param $selected - the string which contains the default value
  1384. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1385. * All Rights Reserved.
  1386. * Contributor(s): ______________________________________..
  1387. */
  1388. function get_select_options_with_id_separate_key($label_list, $key_list, $selected_key, $massupdate = false)
  1389. {
  1390. global $app_strings;
  1391. $select_options = '';
  1392. //for setting null selection values to human readable --None--
  1393. $pattern = "/'0?'></";
  1394. $replacement = "''>".$app_strings['LBL_NONE'].'<';
  1395. if ($massupdate) {
  1396. $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
  1397. }
  1398. if (empty($key_list)) {
  1399. $key_list = array();
  1400. }
  1401. //create the type dropdown domain and set the selected value if $opp value already exists
  1402. foreach ($key_list as $option_key => $option_value) {
  1403. $selected_string = '';
  1404. // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
  1405. // The bug was only happening with one of the users in the drop down. It was being replaced by none.
  1406. if (
  1407. ($option_key != '' && $selected_key == $option_key)
  1408. || (
  1409. $option_key == ''
  1410. && (($selected_key == '' && !$massupdate) || $selected_key == '__SugarMassUpdateClearField__')
  1411. )
  1412. || (is_array($selected_key) && in_array($option_key, $selected_key))
  1413. ) {
  1414. $selected_string = 'selected ';
  1415. }
  1416. $html_value = $option_key;
  1417. $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
  1418. }
  1419. $select_options = preg_replace($pattern, $replacement, $select_options);
  1420. return $select_options;
  1421. }
  1422. /**
  1423. * Call this method instead of die().
  1424. * We print the error message and then die with an appropriate
  1425. * exit code.
  1426. */
  1427. function sugar_die($error_message, $exit_code = 1)
  1428. {
  1429. global $focus;
  1430. sugar_cleanup();
  1431. //echo $error_message;
  1432. //die($exit_code);
  1433. throw new \Exception($error_message, $exit_code);
  1434. }
  1435. /**
  1436. * Create javascript to clear values of all elements in a form.
  1437. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1438. * All Rights Reserved.
  1439. * Contributor(s): ______________________________________..
  1440. */
  1441. function get_clear_form_js()
  1442. {
  1443. $the_script = <<<EOQ
  1444. <script type="text/javascript" language="JavaScript">
  1445. function clear_form(form) {
  1446. var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
  1447. if(typeof(form.advanced) != 'undefined'){
  1448. newLoc += '&advanced=' + form.advanced.value;
  1449. }
  1450. document.location.href= newLoc;
  1451. }
  1452. </script>
  1453. EOQ;
  1454. return $the_script;
  1455. }
  1456. /**
  1457. * Create javascript to set the cursor focus to specific field in a form
  1458. * when the screen is rendered. The field name is currently hardcoded into the
  1459. * the function.
  1460. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1461. * All Rights Reserved.
  1462. * Contributor(s): ______________________________________..
  1463. */
  1464. function get_set_focus_js()
  1465. {
  1466. //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
  1467. $the_script = <<<EOQ
  1468. <script type="text/javascript" language="JavaScript">
  1469. <!--
  1470. function set_focus() {
  1471. if (document.forms.length > 0) {
  1472. for (i = 0; i < document.forms.length; i++) {
  1473. for (j = 0; j < document.forms[i].elements.length; j++) {
  1474. var field = document.forms[i].elements[j];
  1475. if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
  1476. !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
  1477. field.focus();
  1478. if (field.type == "text") {
  1479. field.select();
  1480. }
  1481. break;
  1482. }
  1483. }
  1484. }
  1485. }
  1486. }
  1487. -->
  1488. </script>
  1489. EOQ;
  1490. return $the_script;
  1491. }
  1492. /**
  1493. * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
  1494. * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
  1495. * Explanation: $array is the array you want to sort, 'col1' is the name of the column
  1496. * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
  1497. * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
  1498. * the first - so the array is sorted by the last given column first, then the one before ...
  1499. * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
  1500. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1501. * All Rights Reserved.
  1502. * Contributor(s): ______________________________________..
  1503. */
  1504. function array_csort()
  1505. {
  1506. $args = func_get_args();
  1507. $marray = array_shift($args);
  1508. $i = 0;
  1509. $msortline = 'return(array_multisort(';
  1510. foreach ($args as $arg) {
  1511. ++$i;
  1512. if (is_string($arg)) {
  1513. foreach ($marray as $row) {
  1514. $sortarr[$i][] = $row[$arg];
  1515. }
  1516. } else {
  1517. $sortarr[$i] = $arg;
  1518. }
  1519. $msortline .= '$sortarr['.$i.'],';
  1520. }
  1521. $msortline .= '$marray));';
  1522. eval($msortline);
  1523. return $marray;
  1524. }
  1525. /**
  1526. * Converts localized date format string to jscalendar format
  1527. * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
  1528. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  1529. * All Rights Reserved.
  1530. * Contributor(s): ______________________________________..
  1531. */
  1532. function parse_calendardate($local_format)
  1533. {
  1534. preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
  1535. $calendar_format = '%'.$matches[1].'-%'.$matches[2].'-%'.$matches[3];
  1536. return str_replace(array('y', 'ᅣ1�7', 'a', 'j'), array('Y', 'Y', 'Y', 'd'), $calendar_format);
  1537. }
  1538. function translate($string, $mod = '', $selectedValue = '')
  1539. {
  1540. //$test_start = microtime();
  1541. //static $mod_strings_results = array();
  1542. if (!empty($mod)) {
  1543. global $current_language;
  1544. //Bug 31275
  1545. if (isset($_REQUEST['login_language'])) {
  1546. $current_language = ($_REQUEST['login_language'] == $current_language) ? $current_language : $_REQUEST['login_language'];
  1547. }
  1548. $mod_strings = return_module_language($current_language, $mod);
  1549. if ($mod == '') {
  1550. echo 'Language is <pre>'.$mod_strings.'</pre>';
  1551. }
  1552. } else {
  1553. global $mod_strings;
  1554. }
  1555. $returnValue = '';
  1556. global $app_strings, $app_list_strings;
  1557. if (isset($mod_strings[$string])) {
  1558. $returnValue = $mod_strings[$string];
  1559. } elseif (isset($app_strings[$string])) {
  1560. $returnValue = $app_strings[$string];
  1561. } elseif (isset($app_list_strings[$string])) {
  1562. $returnValue = $app_list_strings[$string];
  1563. } elseif (isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string])) {
  1564. $returnValue = $app_list_strings['moduleList'][$string];
  1565. }
  1566. //$test_end = microtime();
  1567. //
  1568. // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
  1569. //
  1570. // echo("translate results:");
  1571. // $total_time = 0;
  1572. // $total_strings = 0;
  1573. // foreach($mod_strings_results as $key=>$value)
  1574. // {
  1575. // echo("Module $key \t\t time $value \t\t<br>");
  1576. // $total_time += $value;
  1577. // }
  1578. //
  1579. // echo("Total time: $total_time<br>");
  1580. if (empty($returnValue)) {
  1581. return $string;
  1582. }
  1583. // Bug 48996 - Custom enums with '0' value were not returning because of empty check
  1584. // Added a numeric 0 checker to the conditional to allow 0 value indexed to pass
  1585. if (is_array($returnValue) && (!empty($selectedValue) || (is_numeric($selectedValue) && $selectedValue == 0)) && isset($returnValue[$selectedValue])) {
  1586. return $returnValue[$selectedValue];
  1587. }
  1588. return $returnValue;
  1589. }
  1590. function unTranslateNum($num)
  1591. {
  1592. static $dec_sep;
  1593. static $num_grp_sep;
  1594. global $current_user, $sugar_config;
  1595. if ($dec_sep == null) {
  1596. $user_dec_sep = $current_user->getPreference('dec_sep');
  1597. $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
  1598. }
  1599. if ($num_grp_sep == null) {
  1600. $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
  1601. $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
  1602. }
  1603. $num = preg_replace("'".preg_quote($num_grp_sep)."'", '', $num);
  1604. $num = preg_replace("'".preg_quote($dec_sep)."'", '.', $num);
  1605. return $num;
  1606. }
  1607. function add_http($url)
  1608. {
  1609. if (!preg_match('@://@i', $url)) {
  1610. $scheme = 'http';
  1611. if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
  1612. $scheme = 'https';
  1613. }
  1614. return "{$scheme}://{$url}";
  1615. }
  1616. return $url;
  1617. }
  1618. /**
  1619. * returns a default array of XSS tags to clean.
  1620. *
  1621. * @return array
  1622. */
  1623. function getDefaultXssTags()
  1624. {
  1625. $tmp = array(
  1626. 'applet' => 'applet',
  1627. 'base' => 'base',
  1628. 'embed' => 'embed',
  1629. 'form' => 'form',
  1630. 'frame' => 'frame',
  1631. 'frameset' => 'frameset',
  1632. 'iframe' => 'iframe',
  1633. 'import' => "\?import",
  1634. 'layer' => 'layer',
  1635. 'link' => 'link',
  1636. 'object' => 'object',
  1637. 'script' => 'script',
  1638. 'xmp' => 'xmp',
  1639. );
  1640. $ret = base64_encode(serialize($tmp));
  1641. return $ret;
  1642. }
  1643. /**
  1644. * Remove potential xss vectors from strings.
  1645. *
  1646. * @param string str String to search for XSS attack vectors
  1647. *
  1648. * @deprecated
  1649. *
  1650. * @return string
  1651. */
  1652. function remove_xss($str)
  1653. {
  1654. return SugarCleaner::cleanHtml($str, false);
  1655. }
  1656. /**
  1657. * Detects typical XSS attack patterns.
  1658. *
  1659. * @deprecated
  1660. *
  1661. * @param string str String to search for XSS attack vectors
  1662. * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
  1663. *
  1664. * @return array Array of matches, empty on clean string
  1665. */
  1666. function clean_xss($str, $cleanImg = true)
  1667. {
  1668. global $sugar_config;
  1669. if (empty($sugar_config['email_xss'])) {
  1670. $sugar_config['email_xss'] = getDefaultXssTags();
  1671. }
  1672. $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
  1673. // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
  1674. $jsEvents = 'onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|';
  1675. $jsEvents .= 'onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|';
  1676. $jsEvents .= 'onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop';
  1677. $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
  1678. $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
  1679. $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
  1680. $css_url = '#url\(.*\.\w+\)#';
  1681. $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
  1682. $tagmatches = array();
  1683. $matches = array();
  1684. preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
  1685. foreach ($tagmatches[1] as $no => $tag) {
  1686. if (in_array($tag, $xsstags)) {
  1687. // dangerous tag - take out whole
  1688. $matches[] = $tagmatches[0][$no];
  1689. continue;
  1690. }
  1691. $attrmatch = array();
  1692. preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
  1693. if (!empty($attrmatch[0])) {
  1694. $matches = array_merge($matches, $attrmatch[0]);
  1695. }
  1696. }
  1697. $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
  1698. if ($cleanImg) {
  1699. $matches = array_merge($matches,
  1700. xss_check_pattern($imgsrc_regex, $str)
  1701. );
  1702. }
  1703. // cn: bug 13498 - custom white-list of allowed domains that vet remote images
  1704. preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
  1705. if (isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
  1706. if (is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
  1707. // normalize whitelist
  1708. foreach ($sugar_config['security_trusted_domains'] as $k => $v) {
  1709. $sugar_config['security_trusted_domains'][$k] = strtolower($v);
  1710. }
  1711. foreach ($cssUrlMatches[0] as $match) {
  1712. $domain = strtolower(substr(strstr($match, '://'), 3));
  1713. $baseUrl = substr($domain, 0, strpos($domain, '/'));
  1714. if (!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
  1715. $matches[] = $match;
  1716. }
  1717. }
  1718. }
  1719. } else {
  1720. $matches = array_merge($matches, $cssUrlMatches[0]);
  1721. }
  1722. return $matches;
  1723. }
  1724. /**
  1725. * Helper function used by clean_xss() to parse for known-bad vectors.
  1726. *
  1727. * @param string pattern Regex pattern to use
  1728. * @param string str String to parse for badness
  1729. *
  1730. * @return array
  1731. */
  1732. function xss_check_pattern($pattern, $str)
  1733. {
  1734. preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
  1735. return $matches[1];
  1736. }
  1737. /**
  1738. * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it.
  1739. *
  1740. * @param string $str
  1741. * @param string $filter which corresponds to a regular expression to use; choices are:
  1742. * "STANDARD" ( default )
  1743. * "STANDARDSPACE"
  1744. * "FILE"
  1745. * "NUMBER"
  1746. * "SQL_COLUMN_LIST"
  1747. * "PATH_NO_URL"
  1748. * "SAFED_GET"
  1749. * "UNIFIED_SEARCH"
  1750. * "AUTO_INCREMENT"
  1751. * "ALPHANUM"
  1752. * @param bool $dieOnBadData true (default) if you want to die if bad data if found, false if not
  1753. */
  1754. function clean_string($str, $filter = 'STANDARD', $dieOnBadData = true)
  1755. {
  1756. global $sugar_config;
  1757. $filters = array(
  1758. 'STANDARD' => '#[^A-Z0-9\-_\.\@]#i',
  1759. 'STANDARDSPACE' => '#[^A-Z0-9\-_\.\@\ ]#i',
  1760. 'FILE' => '#[^A-Z0-9\-_\.]#i',
  1761. 'NUMBER' => '#[^0-9\-]#i',
  1762. 'SQL_COLUMN_LIST' => '#[^A-Z0-9\(\),_\.]#i',
  1763. 'PATH_NO_URL' => '#://#i',
  1764. 'SAFED_GET' => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
  1765. 'UNIFIED_SEARCH' => '#[\\x00]#', /* cn: bug 3356 & 9236 - MBCS search strings */
  1766. 'AUTO_INCREMENT' => '#[^0-9\-,\ ]#i',
  1767. 'ALPHANUM' => '#[^A-Z0-9\-]#i',
  1768. );
  1769. if (preg_match($filters[$filter], $str)) {
  1770. if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
  1771. $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
  1772. }
  1773. if ($dieOnBadData) {
  1774. die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
  1775. }
  1776. return false;
  1777. } else {
  1778. return $str;
  1779. }
  1780. }
  1781. function clean_special_arguments()
  1782. {
  1783. if (isset($_SERVER['PHP_SELF'])) {
  1784. if (!empty($_SERVER['PHP_SELF'])) {
  1785. clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
  1786. }
  1787. }
  1788. if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) {
  1789. clean_string($_REQUEST['login_theme'], 'STANDARD');
  1790. }
  1791. if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) {
  1792. clean_string($_REQUEST['login_module'], 'STANDARD');
  1793. }
  1794. if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) {
  1795. clean_string($_REQUEST['login_action'], 'STANDARD');
  1796. }
  1797. if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) {
  1798. clean_string($_REQUEST['ck_login_theme_20'], 'STANDARD');
  1799. }
  1800. if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) {
  1801. clean_string($_SESSION['authenticated_user_theme'], 'STANDARD');
  1802. }
  1803. if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) {
  1804. clean_string($_REQUEST['module_name'], 'STANDARD');
  1805. }
  1806. if (!empty($_REQUEST) && !empty($_REQUEST['module'])) {
  1807. clean_string($_REQUEST['module'], 'STANDARD');
  1808. }
  1809. if (!empty($_POST) && !empty($_POST['parent_type'])) {
  1810. clean_string($_POST['parent_type'], 'STANDARD');
  1811. }
  1812. if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) {
  1813. clean_string($_REQUEST['mod_lang'], 'STANDARD');
  1814. }
  1815. if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) {
  1816. clean_string($_SESSION['authenticated_user_language'], 'STANDARD');
  1817. }
  1818. if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) {
  1819. clean_string($_SESSION['dyn_layout_file'], 'PATH_NO_URL');
  1820. }
  1821. if (!empty($_GET) && !empty($_GET['from'])) {
  1822. clean_string($_GET['from']);
  1823. }
  1824. if (!empty($_GET) && !empty($_GET['gmto'])) {
  1825. clean_string($_GET['gmto'], 'NUMBER');
  1826. }
  1827. if (!empty($_GET) && !empty($_GET['case_number'])) {
  1828. clean_string($_GET['case_number'], 'AUTO_INCREMENT');
  1829. }
  1830. if (!empty($_GET) && !empty($_GET['bug_number'])) {
  1831. clean_string($_GET['bug_number'], 'AUTO_INCREMENT');
  1832. }
  1833. if (!empty($_GET) && !empty($_GET['quote_num'])) {
  1834. clean_string($_GET['quote_num'], 'AUTO_INCREMENT');
  1835. }
  1836. clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
  1837. clean_superglobals('offset', 'ALPHANUM');
  1838. clean_superglobals('return_action');
  1839. clean_superglobals('return_module');
  1840. return true;
  1841. }
  1842. /**
  1843. * cleans the given key in superglobals $_GET, $_POST, $_REQUEST.
  1844. */
  1845. function clean_superglobals($key, $filter = 'STANDARD')
  1846. {
  1847. if (isset($_GET[$key])) {
  1848. clean_string($_GET[$key], $filter);
  1849. }
  1850. if (isset($_POST[$key])) {
  1851. clean_string($_POST[$key], $filter);
  1852. }
  1853. if (isset($_REQUEST[$key])) {
  1854. clean_string($_REQUEST[$key], $filter);
  1855. }
  1856. }
  1857. function set_superglobals($key, $val)
  1858. {
  1859. $_GET[$key] = $val;
  1860. $_POST[$key] = $val;
  1861. $_REQUEST[$key] = $val;
  1862. }
  1863. // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
  1864. function clean_incoming_data()
  1865. {
  1866. global $sugar_config;
  1867. global $RAW_REQUEST;
  1868. if (get_magic_quotes_gpc()) {
  1869. // magic quotes screw up data, we'd have to clean up
  1870. $RAW_REQUEST = array_map('cleanup_slashes', $_REQUEST);
  1871. } else {
  1872. $RAW_REQUEST = $_REQUEST;
  1873. }
  1874. if (get_magic_quotes_gpc() == 1) {
  1875. $req = array_map('preprocess_param', $_REQUEST);
  1876. $post = array_map('preprocess_param', $_POST);
  1877. $get = array_map('preprocess_param', $_GET);
  1878. } else {
  1879. $req = array_map('securexss', $_REQUEST);
  1880. $post = array_map('securexss', $_POST);
  1881. $get = array_map('securexss', $_GET);
  1882. }
  1883. // PHP cannot stomp out superglobals reliably
  1884. foreach ($post as $k => $v) {
  1885. $_POST[$k] = $v;
  1886. }
  1887. foreach ($get as $k => $v) {
  1888. $_GET[$k] = $v;
  1889. }
  1890. foreach ($req as $k => $v) {
  1891. $_REQUEST[$k] = $v;
  1892. //ensure the keys are safe as well. If mbstring encoding translation is on, the post keys don't
  1893. //get translated, so scrub the data but don't die
  1894. if (ini_get('mbstring.encoding_translation') === '1') {
  1895. securexsskey($k, false);
  1896. } else {
  1897. securexsskey($k, true);
  1898. }
  1899. }
  1900. // Any additional variables that need to be cleaned should be added here
  1901. if (isset($_REQUEST['login_theme'])) {
  1902. clean_string($_REQUEST['login_theme']);
  1903. }
  1904. if (isset($_REQUEST['login_module'])) {
  1905. clean_string($_REQUEST['login_module']);
  1906. }
  1907. if (isset($_REQUEST['login_action'])) {
  1908. clean_string($_REQUEST['login_action']);
  1909. }
  1910. if (isset($_REQUEST['login_language'])) {
  1911. clean_string($_REQUEST['login_language']);
  1912. }
  1913. if (isset($_REQUEST['action'])) {
  1914. clean_string($_REQUEST['action']);
  1915. }
  1916. if (isset($_REQUEST['module'])) {
  1917. clean_string($_REQUEST['module']);
  1918. }
  1919. if (isset($_REQUEST['record'])) {
  1920. clean_string($_REQUEST['record'], 'STANDARDSPACE');
  1921. }
  1922. if (isset($_SESSION['authenticated_user_theme'])) {
  1923. clean_string($_SESSION['authenticated_user_theme']);
  1924. }
  1925. if (isset($_SESSION['authenticated_user_language'])) {
  1926. clean_string($_SESSION['authenticated_user_language']);
  1927. }
  1928. if (isset($_REQUEST['language'])) {
  1929. clean_string($_REQUEST['language']);
  1930. }
  1931. if (isset($sugar_config['default_theme'])) {
  1932. clean_string($sugar_config['default_theme']);
  1933. }
  1934. if (isset($_REQUEST['offset'])) {
  1935. clean_string($_REQUEST['offset']);
  1936. }
  1937. if (isset($_REQUEST['stamp'])) {
  1938. clean_string($_REQUEST['stamp']);
  1939. }
  1940. if (isset($_REQUEST['lvso'])) {
  1941. set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc') ? 'desc' : 'asc');
  1942. }
  1943. // Clean "offset" and "order_by" parameters in URL
  1944. foreach ($_REQUEST as $key => $val) {
  1945. if (str_end($key, '_offset')) {
  1946. clean_string($_REQUEST[$key], 'ALPHANUM'); // keep this ALPHANUM for disable_count_query
  1947. set_superglobals($key, $_REQUEST[$key]);
  1948. } elseif (str_end($key, '_ORDER_BY')) {
  1949. clean_string($_REQUEST[$key], 'SQL_COLUMN_LIST');
  1950. set_superglobals($key, $_REQUEST[$key]);
  1951. }
  1952. }
  1953. return 0;
  1954. }
  1955. // Returns TRUE if $str begins with $begin
  1956. function str_begin($str, $begin)
  1957. {
  1958. return substr($str, 0, strlen($begin)) == $begin;
  1959. }
  1960. // Returns TRUE if $str ends with $end
  1961. function str_end($str, $end)
  1962. {
  1963. return substr($str, strlen($str) - strlen($end)) == $end;
  1964. }
  1965. function securexss($value)
  1966. {
  1967. if (is_array($value)) {
  1968. $new = array();
  1969. foreach ($value as $key => $val) {
  1970. $new[$key] = securexss($val);
  1971. }
  1972. return $new;
  1973. }
  1974. static $xss_cleanup = array('&quot;' => '&#38;', '"' => '&quot;', "'" => '&#039;', '<' => '&lt;', '>' => '&gt;');
  1975. $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
  1976. $value = preg_replace('/javascript:/i', 'java script:', $value);
  1977. return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
  1978. }
  1979. function securexsskey($value, $die = true)
  1980. {
  1981. global $sugar_config;
  1982. $matches = array();
  1983. preg_match('/[\'"<>]/', $value, $matches);
  1984. if (!empty($matches)) {
  1985. if ($die) {
  1986. die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
  1987. } else {
  1988. unset($_REQUEST[$value]);
  1989. unset($_POST[$value]);
  1990. unset($_GET[$value]);
  1991. }
  1992. }
  1993. }
  1994. function preprocess_param($value)
  1995. {
  1996. if (is_string($value)) {
  1997. if (get_magic_quotes_gpc() == 1) {
  1998. $value = stripslashes($value);
  1999. }
  2000. $value = securexss($value);
  2001. } elseif (is_array($value)) {
  2002. foreach ($value as $key => $element) {
  2003. $value[$key] = preprocess_param($element);
  2004. }
  2005. }
  2006. return $value;
  2007. }
  2008. function cleanup_slashes($value)
  2009. {
  2010. if (is_string($value)) {
  2011. return stripslashes($value);
  2012. }
  2013. return $value;
  2014. }
  2015. function set_register_value($category, $name, $value)
  2016. {
  2017. return sugar_cache_put("{$category}:{$name}", $value);
  2018. }
  2019. function get_register_value($category, $name)
  2020. {
  2021. return sugar_cache_retrieve("{$category}:{$name}");
  2022. }
  2023. function clear_register_value($category, $name)
  2024. {
  2025. return sugar_cache_clear("{$category}:{$name}");
  2026. }
  2027. // this function cleans id's when being imported
  2028. function convert_id($string)
  2029. {
  2030. return preg_replace_callback('|[^A-Za-z0-9\-]|',
  2031. create_function(
  2032. // single quotes are essential here,
  2033. // or alternative escape all $ as \$
  2034. '$matches',
  2035. 'return ord($matches[0]);'
  2036. ), $string);
  2037. }
  2038. /**
  2039. * @deprecated use SugarTheme::getImage()
  2040. */
  2041. function get_image($image, $other_attributes, $width = '', $height = '', $ext = '.gif', $alt = '')
  2042. {
  2043. return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt);
  2044. }
  2045. /**
  2046. * @deprecated use SugarTheme::getImageURL()
  2047. */
  2048. function getImagePath($image_name)
  2049. {
  2050. return SugarThemeRegistry::current()->getImageURL($image_name);
  2051. }
  2052. function getWebPath($relative_path)
  2053. {
  2054. //if it has a :// then it isn't a relative path
  2055. if (substr_count($relative_path, '://') > 0) {
  2056. return $relative_path;
  2057. }
  2058. if (defined('TEMPLATE_URL')) {
  2059. $relative_path = SugarTemplateUtilities::getWebPath($relative_path);
  2060. }
  2061. return $relative_path;
  2062. }
  2063. function getVersionedPath($path, $additional_attrs = '')
  2064. {
  2065. if (empty($GLOBALS['sugar_config']['js_custom_version'])) {
  2066. $GLOBALS['sugar_config']['js_custom_version'] = 1;
  2067. }
  2068. $js_version_key = isset($GLOBALS['js_version_key']) ? $GLOBALS['js_version_key'] : '';
  2069. if (inDeveloperMode()) {
  2070. static $rand;
  2071. if (empty($rand)) {
  2072. $rand = mt_rand();
  2073. }
  2074. $dev = $rand;
  2075. } else {
  2076. $dev = '';
  2077. }
  2078. if (is_array($additional_attrs)) {
  2079. $additional_attrs = implode('|', $additional_attrs);
  2080. }
  2081. // cutting 2 last chars here because since md5 is 32 chars, it's always ==
  2082. $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
  2083. // remove / - it confuses some parsers
  2084. $str = strtr($str, '/+', '-_');
  2085. if (empty($path)) {
  2086. return $str;
  2087. }
  2088. return $path."?v=$str";
  2089. }
  2090. function getVersionedScript($path, $additional_attrs = '')
  2091. {
  2092. return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
  2093. }
  2094. function getJSPath($relative_path, $additional_attrs = '')
  2095. {
  2096. if (defined('TEMPLATE_URL')) {
  2097. $relative_path = SugarTemplateUtilities::getWebPath($relative_path);
  2098. }
  2099. return getVersionedPath($relative_path).(!empty($additional_attrs) ? "&$additional_attrs" : '');
  2100. }
  2101. function getSWFPath($relative_path, $additional_params = '')
  2102. {
  2103. $path = $relative_path;
  2104. if (!empty($additional_params)) {
  2105. $path .= '?'.$additional_params;
  2106. }
  2107. if (defined('TEMPLATE_URL')) {
  2108. $path = TEMPLATE_URL.'/'.$path;
  2109. }
  2110. return $path;
  2111. }
  2112. function getSQLDate($date_str)
  2113. {
  2114. if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/', $date_str, $match)) {
  2115. if (strlen($match[2]) == 1) {
  2116. $match[2] = '0'.$match[2];
  2117. }
  2118. if (strlen($match[1]) == 1) {
  2119. $match[1] = '0'.$match[1];
  2120. }
  2121. return "{$match[3]}-{$match[1]}-{$match[2]}";
  2122. } elseif (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', $date_str, $match)) {
  2123. if (strlen($match[2]) == 1) {
  2124. $match[2] = '0'.$match[2];
  2125. }
  2126. if (strlen($match[1]) == 1) {
  2127. $match[1] = '0'.$match[1];
  2128. }
  2129. return "{$match[3]}-{$match[1]}-{$match[2]}";
  2130. } else {
  2131. return '';
  2132. }
  2133. }
  2134. function clone_history(&$db, $from_id, $to_id, $to_type)
  2135. {
  2136. global $timedate;
  2137. $old_note_id = null;
  2138. $old_filename = null;
  2139. require_once 'include/upload_file.php';
  2140. $tables = array('calls' => 'Call', 'meetings' => 'Meeting', 'notes' => 'Note', 'tasks' => 'Task');
  2141. $location = array('Email' => 'modules/Emails/Email.php',
  2142. 'Call' => 'modules/Calls/Call.php',
  2143. 'Meeting' => 'modules/Meetings/Meeting.php',
  2144. 'Note' => 'modules/Notes/Note.php',
  2145. 'Tasks' => 'modules/Tasks/Task.php',
  2146. );
  2147. foreach ($tables as $table => $bean_class) {
  2148. if (!class_exists($bean_class)) {
  2149. require_once $location[$bean_class];
  2150. }
  2151. $bProcessingNotes = false;
  2152. if ($table == 'notes') {
  2153. $bProcessingNotes = true;
  2154. }
  2155. $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
  2156. $results = $db->query($query);
  2157. while ($row = $db->fetchByAssoc($results)) {
  2158. //retrieve existing record.
  2159. $bean = new $bean_class();
  2160. $bean->retrieve($row['id']);
  2161. //process for new instance.
  2162. if ($bProcessingNotes) {
  2163. $old_note_id = $row['id'];
  2164. $old_filename = $bean->filename;
  2165. }
  2166. $bean->id = null;
  2167. $bean->parent_id = $to_id;
  2168. $bean->parent_type = $to_type;
  2169. if ($to_type == 'Contacts' and in_array('contact_id', $bean->column_fields)) {
  2170. $bean->contact_id = $to_id;
  2171. }
  2172. $bean->update_date_modified = false;
  2173. $bean->update_modified_by = false;
  2174. if (isset($bean->date_modified)) {
  2175. $bean->date_modified = $timedate->to_db($bean->date_modified);
  2176. }
  2177. if (isset($bean->date_entered)) {
  2178. $bean->date_entered = $timedate->to_db($bean->date_entered);
  2179. }
  2180. //save
  2181. $new_id = $bean->save();
  2182. //duplicate the file now. for notes.
  2183. if ($bProcessingNotes && !empty($old_filename)) {
  2184. UploadFile::duplicate_file($old_note_id, $new_id, $old_filename);
  2185. }
  2186. //reset the values needed for attachment duplication.
  2187. $old_note_id = null;
  2188. $old_filename = null;
  2189. }
  2190. }
  2191. }
  2192. function values_to_keys($array)
  2193. {
  2194. $new_array = array();
  2195. if (!is_array($array)) {
  2196. return $new_array;
  2197. }
  2198. foreach ($array as $arr) {
  2199. $new_array[$arr] = $arr;
  2200. }
  2201. return $new_array;
  2202. }
  2203. function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
  2204. {
  2205. foreach ($tables as $table) {
  2206. if ($table == 'emails_beans') {
  2207. $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
  2208. } else {
  2209. $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
  2210. }
  2211. $results = $db->query($query);
  2212. while ($row = $db->fetchByAssoc($results)) {
  2213. $query = "INSERT INTO $table ";
  2214. $names = '';
  2215. $values = '';
  2216. $row[$from_column] = $to_id;
  2217. $row['id'] = create_guid();
  2218. if ($table == 'emails_beans') {
  2219. $row['bean_module'] == 'Contacts';
  2220. }
  2221. foreach ($row as $name => $value) {
  2222. if (empty($names)) {
  2223. $names .= $name;
  2224. $values .= "'$value'";
  2225. } else {
  2226. $names .= ', '.$name;
  2227. $values .= ", '$value'";
  2228. }
  2229. }
  2230. $query .= "($names) VALUES ($values)";
  2231. $db->query($query);
  2232. }
  2233. }
  2234. }
  2235. function get_unlinked_email_query($type, $bean)
  2236. {
  2237. global $current_user;
  2238. $return_array['select'] = 'SELECT emails.id ';
  2239. $return_array['from'] = 'FROM emails ';
  2240. $return_array['where'] = '';
  2241. $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
  2242. join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
  2243. eabr.email_address_id = eear.email_address_id and eabr.deleted=0
  2244. where eear.deleted=0 and eear.email_id not in
  2245. (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
  2246. ) derivedemails on derivedemails.email_id = emails.id";
  2247. $return_array['join_tables'][0] = '';
  2248. if (isset($type) and !empty($type['return_as_array'])) {
  2249. return $return_array;
  2250. }
  2251. return $return_array['select'].$return_array['from'].$return_array['where'].$return_array['join'];
  2252. } // fn
  2253. function get_emails_by_assign_or_link($params)
  2254. {
  2255. $relation = $params['link'];
  2256. $bean = $GLOBALS['app']->controller->bean;
  2257. if (empty($bean->$relation)) {
  2258. $bean->load_relationship($relation);
  2259. }
  2260. if (empty($bean->$relation)) {
  2261. $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
  2262. return array();
  2263. }
  2264. $rel_module = $bean->$relation->getRelatedModuleName();
  2265. $rel_join = $bean->$relation->getJoin(array(
  2266. 'join_table_alias' => 'link_bean',
  2267. 'join_table_link_alias' => 'linkt',
  2268. ));
  2269. $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
  2270. $return_array['select'] = 'SELECT DISTINCT emails.id ';
  2271. $return_array['from'] = 'FROM emails ';
  2272. $return_array['join'] = array();
  2273. // directly assigned emails
  2274. $return_array['join'][] = "
  2275. SELECT
  2276. eb.email_id,
  2277. 'direct' source
  2278. FROM
  2279. emails_beans eb
  2280. WHERE
  2281. eb.bean_module = '{$bean->module_dir}'
  2282. AND eb.bean_id = '{$bean->id}'
  2283. AND eb.deleted=0
  2284. ";
  2285. // Related by directly by email
  2286. $return_array['join'][] = "
  2287. SELECT DISTINCT
  2288. eear.email_id,
  2289. 'relate' source
  2290. FROM
  2291. emails_email_addr_rel eear
  2292. INNER JOIN
  2293. email_addr_bean_rel eabr
  2294. ON
  2295. eabr.bean_id ='{$bean->id}'
  2296. AND eabr.bean_module = '{$bean->module_dir}'
  2297. AND eabr.email_address_id = eear.email_address_id
  2298. AND eabr.deleted=0
  2299. WHERE
  2300. eear.deleted=0
  2301. ";
  2302. $showEmailsOfRelatedContacts = empty($bean->field_defs[$relation]['hide_history_contacts_emails']);
  2303. if (!empty($GLOBALS['sugar_config']['hide_history_contacts_emails']) && isset($GLOBALS['sugar_config']['hide_history_contacts_emails'][$bean->module_name])) {
  2304. $showEmailsOfRelatedContacts = empty($GLOBALS['sugar_config']['hide_history_contacts_emails'][$bean->module_name]);
  2305. }
  2306. if ($showEmailsOfRelatedContacts) {
  2307. // Assigned to contacts
  2308. $return_array['join'][] = "
  2309. SELECT DISTINCT
  2310. eb.email_id,
  2311. 'contact' source
  2312. FROM
  2313. emails_beans eb
  2314. $rel_join AND link_bean.id = eb.bean_id
  2315. WHERE
  2316. eb.bean_module = '$rel_module'
  2317. AND eb.deleted=0
  2318. ";
  2319. // Related by email to linked contact
  2320. $return_array['join'][] = "
  2321. SELECT DISTINCT
  2322. eear.email_id,
  2323. 'relate_contact' source
  2324. FROM
  2325. emails_email_addr_rel eear
  2326. INNER JOIN
  2327. email_addr_bean_rel eabr
  2328. ON
  2329. eabr.email_address_id=eear.email_address_id
  2330. AND eabr.bean_module = '$rel_module'
  2331. AND eabr.deleted=0
  2332. $rel_join AND link_bean.id = eabr.bean_id
  2333. WHERE
  2334. eear.deleted=0
  2335. ";
  2336. }
  2337. $return_array['join'] = ' INNER JOIN ('.implode(' UNION ', $return_array['join']).') email_ids ON emails.id=email_ids.email_id ';
  2338. $return_array['where'] = ' WHERE emails.deleted=0 ';
  2339. //$return_array['join'] = '';
  2340. $return_array['join_tables'][0] = '';
  2341. if ($bean->object_name == 'Case' && !empty($bean->case_number)) {
  2342. $where = str_replace('%1', $bean->case_number, $bean->getEmailSubjectMacro());
  2343. $return_array['where'] .= "\n AND (email_ids.source = 'direct' OR emails.name LIKE '%$where%')";
  2344. }
  2345. return $return_array;
  2346. }
  2347. /**
  2348. * Check to see if the number is empty or non-zero.
  2349. *
  2350. * @param $value
  2351. *
  2352. * @return bool
  2353. **/
  2354. function number_empty($value)
  2355. {
  2356. return empty($value) && $value != '0';
  2357. }
  2358. function get_bean_select_array($add_blank = true, $bean_name, $display_columns, $where = '', $order_by = '', $blank_is_none = false)
  2359. {
  2360. global $beanFiles;
  2361. require_once $beanFiles[$bean_name];
  2362. $focus = new $bean_name();
  2363. $user_array = array();
  2364. $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name.$display_columns.$where.$order_by;
  2365. $user_array = get_register_value('select_array', $key);
  2366. if (!$user_array) {
  2367. $db = DBManagerFactory::getInstance();
  2368. $temp_result = array();
  2369. $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
  2370. $query .= 'where ';
  2371. if ($where != '') {
  2372. $query .= $where.' AND ';
  2373. }
  2374. $query .= " {$focus->table_name}.deleted=0";
  2375. /* BEGIN - SECURITY GROUPS */
  2376. global $current_user, $sugar_config;
  2377. if ($focus->module_dir == 'Users' && !is_admin($current_user)
  2378. && isset($sugar_config['securitysuite_filter_user_list'])
  2379. && $sugar_config['securitysuite_filter_user_list'] == true
  2380. ) {
  2381. require_once 'modules/SecurityGroups/SecurityGroup.php';
  2382. $group_where = SecurityGroup::getGroupUsersWhere($current_user->id);
  2383. $query .= ' AND ('.$group_where.') ';
  2384. } elseif ($focus->bean_implements('ACL') && ACLController::requireSecurityGroup($focus->module_dir, 'list')) {
  2385. require_once 'modules/SecurityGroups/SecurityGroup.php';
  2386. $owner_where = $focus->getOwnerWhere($current_user->id);
  2387. $group_where = SecurityGroup::getGroupWhere($focus->table_name, $focus->module_dir, $current_user->id);
  2388. if (!empty($owner_where)) {
  2389. $query .= ' AND ('.$owner_where.' or '.$group_where.') ';
  2390. } else {
  2391. $query .= ' AND '.$group_where;
  2392. }
  2393. }
  2394. /* END - SECURITY GROUPS */
  2395. if ($order_by != '') {
  2396. $query .= " order by {$focus->table_name}.{$order_by}";
  2397. }
  2398. $GLOBALS['log']->debug("get_user_array query: $query");
  2399. $result = $db->query($query, true, 'Error filling in user array: ');
  2400. if ($add_blank == true) {
  2401. // Add in a blank row
  2402. if ($blank_is_none == true) { // set 'blank row' to "--None--"
  2403. global $app_strings;
  2404. $temp_result[''] = $app_strings['LBL_NONE'];
  2405. } else {
  2406. $temp_result[''] = '';
  2407. }
  2408. }
  2409. // Get the id and the name.
  2410. while ($row = $db->fetchByAssoc($result)) {
  2411. $temp_result[$row['id']] = $row['display'];
  2412. }
  2413. $user_array = $temp_result;
  2414. set_register_value('select_array', $key, $temp_result);
  2415. }
  2416. return $user_array;
  2417. }
  2418. /**
  2419. * @param unknown_type $listArray
  2420. */
  2421. // function parse_list_modules
  2422. // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
  2423. function parse_list_modules(&$listArray)
  2424. {
  2425. global $modListHeader;
  2426. $returnArray = array();
  2427. foreach ($listArray as $optionName => $optionVal) {
  2428. if (array_key_exists($optionName, $modListHeader)) {
  2429. $returnArray[$optionName] = $optionVal;
  2430. }
  2431. // special case for projects
  2432. if (array_key_exists('Project', $modListHeader)) {
  2433. $returnArray['ProjectTask'] = $listArray['ProjectTask'];
  2434. }
  2435. }
  2436. $acldenied = ACLController::disabledModuleList($listArray, false);
  2437. foreach ($acldenied as $denied) {
  2438. unset($returnArray[$denied]);
  2439. }
  2440. asort($returnArray);
  2441. return $returnArray;
  2442. }
  2443. function display_notice($msg = false)
  2444. {
  2445. global $error_notice;
  2446. //no error notice - lets just display the error to the user
  2447. if (!isset($error_notice)) {
  2448. echo '<br>'.$msg.'<br>';
  2449. } else {
  2450. $error_notice .= $msg.'<br>';
  2451. }
  2452. }
  2453. /* checks if it is a number that at least has the plus at the beginning.
  2454. */
  2455. function skype_formatted($number)
  2456. {
  2457. //kbrill - BUG #15375
  2458. if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'Popup') {
  2459. return false;
  2460. } else {
  2461. return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
  2462. }
  2463. // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
  2464. }
  2465. function format_skype($number)
  2466. {
  2467. return preg_replace('/[^\+0-9]/', '', $number);
  2468. }
  2469. function insert_charset_header()
  2470. {
  2471. header('Content-Type: text/html; charset=UTF-8');
  2472. }
  2473. function getCurrentURL()
  2474. {
  2475. $href = 'http:';
  2476. if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
  2477. $href = 'https:';
  2478. }
  2479. $href .= '//'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
  2480. return $href;
  2481. }
  2482. function javascript_escape($str)
  2483. {
  2484. $new_str = '';
  2485. for ($i = 0; $i < strlen($str); ++$i) {
  2486. if (ord(substr($str, $i, 1)) == 10) {
  2487. $new_str .= '\n';
  2488. } elseif (ord(substr($str, $i, 1)) == 13) {
  2489. $new_str .= '\r';
  2490. } else {
  2491. $new_str .= $str{$i};
  2492. }
  2493. }
  2494. $new_str = str_replace("'", "\\'", $new_str);
  2495. return $new_str;
  2496. }
  2497. function js_escape($str, $keep = true)
  2498. {
  2499. $str = html_entity_decode(str_replace('\\', '', $str), ENT_QUOTES);
  2500. if ($keep) {
  2501. $str = javascript_escape($str);
  2502. } else {
  2503. $str = str_replace("'", ' ', $str);
  2504. $str = str_replace('"', ' ', $str);
  2505. }
  2506. return $str;
  2507. //end function js_escape
  2508. }
  2509. function br2nl($str)
  2510. {
  2511. $regex = '#<[^>]+br.+?>#i';
  2512. preg_match_all($regex, $str, $matches);
  2513. foreach ($matches[0] as $match) {
  2514. $str = str_replace($match, '<br>', $str);
  2515. }
  2516. $brs = array('<br>', '<br/>', '<br />');
  2517. $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
  2518. $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
  2519. $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
  2520. $str = str_ireplace($brs, "\n", $str); // to retrieve it
  2521. return $str;
  2522. }
  2523. /**
  2524. * Private helper function for displaying the contents of a given variable.
  2525. * This function is only intended to be used for SugarCRM internal development.
  2526. * The ppd stands for Pre Print Die.
  2527. */
  2528. function _ppd($mixed)
  2529. {
  2530. }
  2531. /**
  2532. * Private helper function for displaying the contents of a given variable in
  2533. * the Logger. This function is only intended to be used for SugarCRM internal
  2534. * development. The pp stands for Pre Print.
  2535. *
  2536. * @param $mixed var to print_r()
  2537. * @param $die boolean end script flow
  2538. * @param $displayStackTrace also show stack trace
  2539. */
  2540. function _ppl($mixed, $die = false, $displayStackTrace = false, $loglevel = 'fatal')
  2541. {
  2542. if (!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
  2543. $GLOBALS['log'] = LoggerManager:: getLogger('SugarCRM');
  2544. }
  2545. $mix = print_r($mixed, true); // send print_r() output to $mix
  2546. $stack = debug_backtrace();
  2547. $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
  2548. $GLOBALS['log']->$loglevel($mix);
  2549. if ($displayStackTrace) {
  2550. foreach ($stack as $position) {
  2551. $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
  2552. }
  2553. }
  2554. $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
  2555. $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
  2556. if ($die) {
  2557. die();
  2558. }
  2559. }
  2560. /**
  2561. * private helper function to quickly show the major, direct, field attributes of a given bean.
  2562. * The ppf stands for Pre[formatted] Print Focus [object].
  2563. *
  2564. * @param object bean The focus bean
  2565. */
  2566. function _ppf($bean, $die = false)
  2567. {
  2568. }
  2569. /**
  2570. * Private helper function for displaying the contents of a given variable.
  2571. * This function is only intended to be used for SugarCRM internal development.
  2572. * The pp stands for Pre Print.
  2573. */
  2574. function _pp($mixed)
  2575. {
  2576. }
  2577. /**
  2578. * Private helper function for displaying the contents of a given variable.
  2579. * This function is only intended to be used for SugarCRM internal development.
  2580. * The pp stands for Pre Print.
  2581. */
  2582. function _pstack_trace($mixed = null)
  2583. {
  2584. }
  2585. /**
  2586. * Private helper function for displaying the contents of a given variable.
  2587. * This function is only intended to be used for SugarCRM internal development.
  2588. * The pp stands for Pre Print Trace.
  2589. */
  2590. function _ppt($mixed, $textOnly = false)
  2591. {
  2592. }
  2593. /**
  2594. * Private helper function for displaying the contents of a given variable.
  2595. * This function is only intended to be used for SugarCRM internal development.
  2596. * The pp stands for Pre Print Trace Die.
  2597. */
  2598. function _pptd($mixed)
  2599. {
  2600. }
  2601. /**
  2602. * Private helper function for decoding javascript UTF8
  2603. * This function is only intended to be used for SugarCRM internal development.
  2604. */
  2605. function decodeJavascriptUTF8($str)
  2606. {
  2607. }
  2608. /**
  2609. * Will check if a given PHP version string is supported (tested on this ver),
  2610. * unsupported (results unknown), or invalid (something will break on this
  2611. * ver). Do not pass in any pararameter to default to a check against the
  2612. * current environment's PHP version.
  2613. *
  2614. * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
  2615. */
  2616. function check_php_version($sys_php_version = '')
  2617. {
  2618. $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
  2619. // versions below $min_considered_php_version considered invalid by default,
  2620. // versions equal to or above this ver will be considered depending
  2621. // on the rules that follow
  2622. $min_considered_php_version = '5.3.0';
  2623. // only the supported versions,
  2624. // should be mutually exclusive with $invalid_php_versions
  2625. $supported_php_versions = array(
  2626. '5.3.0',
  2627. );
  2628. // invalid versions above the $min_considered_php_version,
  2629. // should be mutually exclusive with $supported_php_versions
  2630. // SugarCRM prohibits install on PHP 5.2.7 on all platforms
  2631. $invalid_php_versions = array('5.2.7');
  2632. // default unsupported
  2633. $retval = 0;
  2634. // versions below $min_considered_php_version are invalid
  2635. if (1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
  2636. $retval = -1;
  2637. }
  2638. // supported version check overrides default unsupported
  2639. foreach ($supported_php_versions as $ver) {
  2640. if (1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version, $ver) !== false) {
  2641. $retval = 1;
  2642. break;
  2643. }
  2644. }
  2645. // invalid version check overrides default unsupported
  2646. foreach ($invalid_php_versions as $ver) {
  2647. if (1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version, $ver) !== false) {
  2648. $retval = -1;
  2649. break;
  2650. }
  2651. }
  2652. //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
  2653. //and the php version contains 'rh' characters
  2654. if (strpos($sys_php_version, 'rh') !== false) {
  2655. $retval = 1;
  2656. }
  2657. return $retval;
  2658. }
  2659. /**
  2660. * Will check if a given IIS version string is supported (tested on this ver),
  2661. * unsupported (results unknown), or invalid (something will break on this
  2662. * ver).
  2663. *
  2664. * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
  2665. */
  2666. function check_iis_version($sys_iis_version = '')
  2667. {
  2668. $server_software = $_SERVER['SERVER_SOFTWARE'];
  2669. $iis_version = '';
  2670. if (strpos($server_software, 'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out)) {
  2671. $iis_version = $out[1][0];
  2672. }
  2673. $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';
  2678. // only the supported versions,
  2679. // should be mutually exclusive with $invalid_iis_versions
  2680. $supported_iis_versions = array('6.0', '7.0');
  2681. $unsupported_iis_versions = array();
  2682. $invalid_iis_versions = array('5.0');
  2683. // default unsupported
  2684. $retval = 0;
  2685. // versions below $min_considered_iis_version are invalid
  2686. if (1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
  2687. $retval = -1;
  2688. }
  2689. // supported version check overrides default unsupported
  2690. foreach ($supported_iis_versions as $ver) {
  2691. if (1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version, $ver) !== false) {
  2692. $retval = 1;
  2693. break;
  2694. }
  2695. }
  2696. // unsupported version check overrides default unsupported
  2697. foreach ($unsupported_iis_versions as $ver) {
  2698. if (1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version, $ver) !== false) {
  2699. $retval = 0;
  2700. break;
  2701. }
  2702. }
  2703. // invalid version check overrides default unsupported
  2704. foreach ($invalid_iis_versions as $ver) {
  2705. if (1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version, $ver) !== false) {
  2706. $retval = -1;
  2707. break;
  2708. }
  2709. }
  2710. return $retval;
  2711. }
  2712. function pre_login_check()
  2713. {
  2714. global $action, $login_error;
  2715. if (!empty($action) && $action == 'Login') {
  2716. if (!empty($login_error)) {
  2717. $login_error = htmlentities($login_error);
  2718. $login_error = str_replace(array('&lt;pre&gt;', '&lt;/pre&gt;', "\r\n", "\n"), '<br>', $login_error);
  2719. $_SESSION['login_error'] = $login_error;
  2720. echo '<script>
  2721. function set_focus() {}
  2722. if(document.getElementById("post_error")) {
  2723. document.getElementById("post_error").innerHTML="'.$login_error.'";
  2724. document.getElementById("cant_login").value=1;
  2725. document.getElementById("login_button").disabled = true;
  2726. document.getElementById("user_name").disabled = true;
  2727. //document.getElementById("user_password").disabled = true;
  2728. }
  2729. </script>';
  2730. }
  2731. }
  2732. }
  2733. function sugar_cleanup($exit = false)
  2734. {
  2735. static $called = false;
  2736. if ($called) {
  2737. return;
  2738. }
  2739. $called = true;
  2740. set_include_path(realpath(dirname(__FILE__).'/..').PATH_SEPARATOR.get_include_path());
  2741. chdir(realpath(dirname(__FILE__).'/..'));
  2742. global $sugar_config;
  2743. require_once 'include/utils/LogicHook.php';
  2744. LogicHook::initialize();
  2745. $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
  2746. //added this check to avoid errors during install.
  2747. if (empty($sugar_config['dbconfig'])) {
  2748. if ($exit) {
  2749. exit;
  2750. } else {
  2751. return;
  2752. }
  2753. }
  2754. if (!class_exists('Tracker', true)) {
  2755. require_once 'modules/Trackers/Tracker.php';
  2756. }
  2757. Tracker::logPage();
  2758. // Now write the cached tracker_queries
  2759. if (!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
  2760. if (isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceof User) {
  2761. $GLOBALS['current_user']->savePreferencesToDB();
  2762. }
  2763. }
  2764. //check to see if this is not an `ajax call AND the user preference error flag is set
  2765. if (
  2766. (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
  2767. && ($_REQUEST['action'] != 'modulelistmenu' && $_REQUEST['action'] != 'DynamicAction')
  2768. && ($_REQUEST['action'] != 'favorites' && $_REQUEST['action'] != 'DynamicAction')
  2769. && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'])
  2770. && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'])
  2771. ) {
  2772. global $app_strings;
  2773. //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
  2774. $err_mess = $app_strings['ERROR_USER_PREFS'];
  2775. $_SESSION['USER_PREFRENCE_ERRORS'] = false;
  2776. echo "
  2777. <script>
  2778. ajaxStatus.flashStatus('$err_mess',7000);
  2779. </script>";
  2780. }
  2781. pre_login_check();
  2782. if (class_exists('DBManagerFactory')) {
  2783. $db = DBManagerFactory::getInstance();
  2784. $db->disconnect();
  2785. if ($exit) {
  2786. exit;
  2787. }
  2788. }
  2789. }
  2790. register_shutdown_function('sugar_cleanup');
  2791. /*
  2792. check_logic_hook - checks to see if your custom logic is in the logic file
  2793. if not, it will add it. If the file isn't built yet, it will create the file
  2794. */
  2795. function check_logic_hook_file($module_name, $event, $action_array)
  2796. {
  2797. require_once 'include/utils/logic_utils.php';
  2798. $add_logic = false;
  2799. if (file_exists("custom/modules/$module_name/logic_hooks.php")) {
  2800. $hook_array = get_hook_array($module_name);
  2801. if (check_existing_element($hook_array, $event, $action_array) == true) {
  2802. //the hook at hand is present, so do nothing
  2803. } else {
  2804. $add_logic = true;
  2805. $logic_count = 0;
  2806. if (!empty($hook_array[$event])) {
  2807. $logic_count = count($hook_array[$event]);
  2808. }
  2809. if ($action_array[0] == '') {
  2810. $action_array[0] = $logic_count + 1;
  2811. }
  2812. $hook_array[$event][] = $action_array;
  2813. }
  2814. //end if the file exists already
  2815. } else {
  2816. $add_logic = true;
  2817. if ($action_array[0] == '') {
  2818. $action_array[0] = 1;
  2819. }
  2820. $hook_array = array();
  2821. $hook_array[$event][] = $action_array;
  2822. //end if else file exists already
  2823. }
  2824. if ($add_logic == true) {
  2825. //reorder array by element[0]
  2826. //$hook_array = reorder_array($hook_array, $event);
  2827. //!!!Finish this above TODO
  2828. $new_contents = replace_or_add_logic_type($hook_array);
  2829. write_logic_file($module_name, $new_contents);
  2830. //end if add_element is true
  2831. }
  2832. //end function check_logic_hook_file
  2833. }
  2834. function remove_logic_hook($module_name, $event, $action_array)
  2835. {
  2836. require_once 'include/utils/logic_utils.php';
  2837. $add_logic = false;
  2838. if (file_exists('custom/modules/'.$module_name.'/logic_hooks.php')) {
  2839. // The file exists, let's make sure the hook is there
  2840. $hook_array = get_hook_array($module_name);
  2841. if (check_existing_element($hook_array, $event, $action_array) == true) {
  2842. // The hook is there, time to take it out.
  2843. foreach ($hook_array[$event] as $i => $hook) {
  2844. // We don't do a full comparison below just in case the filename changes
  2845. if ($hook[0] == $action_array[0]
  2846. && $hook[1] == $action_array[1]
  2847. && $hook[3] == $action_array[3]
  2848. && $hook[4] == $action_array[4]
  2849. ) {
  2850. unset($hook_array[$event][$i]);
  2851. }
  2852. }
  2853. $new_contents = replace_or_add_logic_type($hook_array);
  2854. write_logic_file($module_name, $new_contents);
  2855. }
  2856. }
  2857. }
  2858. function display_stack_trace($textOnly = false)
  2859. {
  2860. $stack = debug_backtrace();
  2861. echo "\n\n display_stack_trace caller, file: ".$stack[0]['file'].' line#: '.$stack[0]['line'];
  2862. if (!$textOnly) {
  2863. echo '<br>';
  2864. }
  2865. $first = true;
  2866. $out = '';
  2867. foreach ($stack as $item) {
  2868. $file = '';
  2869. $class = '';
  2870. $line = '';
  2871. $function = '';
  2872. if (isset($item['file'])) {
  2873. $file = $item['file'];
  2874. }
  2875. if (isset($item['class'])) {
  2876. $class = $item['class'];
  2877. }
  2878. if (isset($item['line'])) {
  2879. $line = $item['line'];
  2880. }
  2881. if (isset($item['function'])) {
  2882. $function = $item['function'];
  2883. }
  2884. if (!$first) {
  2885. if (!$textOnly) {
  2886. $out .= '<font color="black"><b>';
  2887. }
  2888. $out .= $file;
  2889. if (!$textOnly) {
  2890. $out .= '</b></font><font color="blue">';
  2891. }
  2892. $out .= "[L:{$line}]";
  2893. if (!$textOnly) {
  2894. $out .= '</font><font color="red">';
  2895. }
  2896. $out .= "({$class}:{$function})";
  2897. if (!$textOnly) {
  2898. $out .= '</font><br>';
  2899. } else {
  2900. $out .= "\n";
  2901. }
  2902. } else {
  2903. $first = false;
  2904. }
  2905. }
  2906. echo $out;
  2907. }
  2908. function StackTraceErrorHandler($errno, $errstr, $errfile, $errline, $errcontext)
  2909. {
  2910. $error_msg = " $errstr occurred in <b>$errfile</b> on line $errline [".date('Y-m-d H:i:s').']';
  2911. $halt_script = true;
  2912. switch ($errno) {
  2913. case 2048 :
  2914. return; //depricated we have lots of these ignore them
  2915. case E_USER_NOTICE:
  2916. case E_NOTICE:
  2917. if (error_reporting() & E_NOTICE) {
  2918. $halt_script = false;
  2919. $type = 'Notice';
  2920. } else {
  2921. return;
  2922. }
  2923. break;
  2924. case E_USER_WARNING:
  2925. case E_COMPILE_WARNING:
  2926. case E_CORE_WARNING:
  2927. case E_WARNING:
  2928. $halt_script = false;
  2929. $type = 'Warning';
  2930. break;
  2931. case E_USER_ERROR:
  2932. case E_COMPILE_ERROR:
  2933. case E_CORE_ERROR:
  2934. case E_ERROR:
  2935. $type = 'Fatal Error';
  2936. break;
  2937. case E_PARSE:
  2938. $type = 'Parse Error';
  2939. break;
  2940. default:
  2941. //don't know what it is might not be so bad
  2942. $halt_script = false;
  2943. $type = "Unknown Error ($errno)";
  2944. break;
  2945. }
  2946. $error_msg = '<b>'.$type.'</b>:'.$error_msg;
  2947. echo $error_msg;
  2948. display_stack_trace();
  2949. if ($halt_script) {
  2950. exit -1;
  2951. }
  2952. }
  2953. if (isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']) {
  2954. set_error_handler('StackTraceErrorHandler');
  2955. }
  2956. function get_sub_cookies($name)
  2957. {
  2958. $cookies = array();
  2959. if (isset($_COOKIE[$name])) {
  2960. $subs = explode('#', $_COOKIE[$name]);
  2961. foreach ($subs as $cookie) {
  2962. if (!empty($cookie)) {
  2963. $cookie = explode('=', $cookie);
  2964. $cookies[$cookie[0]] = $cookie[1];
  2965. }
  2966. }
  2967. }
  2968. return $cookies;
  2969. }
  2970. function mark_delete_components($sub_object_array, $run_second_level = false, $sub_sub_array = '')
  2971. {
  2972. if (!empty($sub_object_array)) {
  2973. foreach ($sub_object_array as $sub_object) {
  2974. //run_second level is set to true if you need to remove sub-sub components
  2975. if ($run_second_level == true) {
  2976. mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'], $sub_sub_array['rel_module']));
  2977. //end if run_second_level is true
  2978. }
  2979. $sub_object->mark_deleted($sub_object->id);
  2980. //end foreach sub component
  2981. }
  2982. //end if this is not empty
  2983. }
  2984. //end function mark_delete_components
  2985. }
  2986. /**
  2987. * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
  2988. */
  2989. function return_bytes($val)
  2990. {
  2991. $val = trim($val);
  2992. $last = strtolower($val{strlen($val) - 1});
  2993. switch ($last) {
  2994. // The 'G' modifier is available since PHP 5.1.0
  2995. case 'g':
  2996. $val *= 1024;
  2997. case 'm':
  2998. $val *= 1024;
  2999. case 'k':
  3000. $val *= 1024;
  3001. }
  3002. return $val;
  3003. }
  3004. /**
  3005. * Adds the href HTML tags around any URL in the $string.
  3006. */
  3007. function url2html($string)
  3008. {
  3009. //
  3010. $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
  3011. return $return_string;
  3012. }
  3013. // End customization by Julian
  3014. /**
  3015. * tries to determine whether the Host machine is a Windows machine.
  3016. */
  3017. function is_windows()
  3018. {
  3019. static $is_windows = null;
  3020. if (!isset($is_windows)) {
  3021. $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
  3022. }
  3023. return $is_windows;
  3024. }
  3025. /**
  3026. * equivalent for windows filesystem for PHP's is_writable().
  3027. *
  3028. * @param string file Full path to the file/dir
  3029. *
  3030. * @return bool true if writable
  3031. */
  3032. function is_writable_windows($file)
  3033. {
  3034. if ($file{strlen($file) - 1} == '/') {
  3035. return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
  3036. }
  3037. // the assumption here is that Windows has an inherited permissions scheme
  3038. // any file that is a descendant of an unwritable directory will inherit
  3039. // that property and will trigger a failure below.
  3040. if (is_dir($file)) {
  3041. return true;
  3042. }
  3043. $file = str_replace('/', '\\', $file);
  3044. if (file_exists($file)) {
  3045. if (!($f = @sugar_fopen($file, 'r+'))) {
  3046. return false;
  3047. }
  3048. fclose($f);
  3049. return true;
  3050. }
  3051. if (!($f = @sugar_fopen($file, 'w'))) {
  3052. return false;
  3053. }
  3054. fclose($f);
  3055. unlink($file);
  3056. return true;
  3057. }
  3058. /**
  3059. * best guesses Timezone based on webserver's TZ settings.
  3060. */
  3061. function lookupTimezone($userOffset = 0)
  3062. {
  3063. return TimeDate::guessTimezone($userOffset);
  3064. }
  3065. function convert_module_to_singular($module_array)
  3066. {
  3067. global $beanList;
  3068. foreach ($module_array as $key => $value) {
  3069. if (!empty($beanList[$value])) {
  3070. $module_array[$key] = $beanList[$value];
  3071. }
  3072. if ($value == 'Cases') {
  3073. $module_array[$key] = 'Case';
  3074. }
  3075. if ($key == 'projecttask') {
  3076. $module_array['ProjectTask'] = 'Project Task';
  3077. unset($module_array[$key]);
  3078. }
  3079. }
  3080. return $module_array;
  3081. //end function convert_module_to_singular
  3082. }
  3083. /*
  3084. * Given the bean_name which may be plural or singular return the singular
  3085. * bean_name. This is important when you need to include files.
  3086. */
  3087. function get_singular_bean_name($bean_name)
  3088. {
  3089. global $beanFiles, $beanList;
  3090. if (array_key_exists($bean_name, $beanList)) {
  3091. return $beanList[$bean_name];
  3092. } else {
  3093. return $bean_name;
  3094. }
  3095. }
  3096. /*
  3097. * Given the potential module name (singular name, renamed module name)
  3098. * Return the real internal module name.
  3099. */
  3100. function get_module_from_singular($singular)
  3101. {
  3102. // find the internal module name for a singular name
  3103. if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
  3104. $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
  3105. foreach ($singular_modules as $mod_name => $sin_name) {
  3106. if ($singular == $sin_name and $mod_name != $sin_name) {
  3107. return $mod_name;
  3108. }
  3109. }
  3110. }
  3111. // find the internal module name for a renamed module
  3112. if (isset($GLOBALS['app_list_strings']['moduleList'])) {
  3113. $moduleList = $GLOBALS['app_list_strings']['moduleList'];
  3114. foreach ($moduleList as $mod_name => $name) {
  3115. if ($singular == $name and $mod_name != $name) {
  3116. return $mod_name;
  3117. }
  3118. }
  3119. }
  3120. // if it's not a singular name, nor a renamed name, return the original value
  3121. return $singular;
  3122. }
  3123. function get_label($label_tag, $temp_module_strings)
  3124. {
  3125. global $app_strings;
  3126. if (!empty($temp_module_strings[$label_tag])) {
  3127. $label_name = $temp_module_strings[$label_tag];
  3128. } else {
  3129. if (!empty($app_strings[$label_tag])) {
  3130. $label_name = $app_strings[$label_tag];
  3131. } else {
  3132. $label_name = $label_tag;
  3133. }
  3134. }
  3135. return $label_name;
  3136. //end function get_label
  3137. }
  3138. function search_filter_rel_info(&$focus, $tar_rel_module, $relationship_name)
  3139. {
  3140. $rel_list = array();
  3141. foreach ($focus->relationship_fields as $rel_key => $rel_value) {
  3142. if ($rel_value == $relationship_name) {
  3143. $temp_bean = BeanFactory::getBean($tar_rel_module, $focus->$rel_key);
  3144. if ($temp_bean) {
  3145. $rel_list[] = $temp_bean;
  3146. return $rel_list;
  3147. }
  3148. }
  3149. }
  3150. foreach ($focus->field_defs as $field_name => $field_def) {
  3151. //Check if the relationship_name matches a "relate" field
  3152. if (!empty($field_def['type']) && $field_def['type'] == 'relate'
  3153. && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
  3154. && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
  3155. && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name
  3156. ) {
  3157. $temp_bean = BeanFactory::getBean($tar_rel_module, $field_def['id_name']);
  3158. if ($temp_bean) {
  3159. $rel_list[] = $temp_bean;
  3160. return $rel_list;
  3161. }
  3162. //Check if the relationship_name matches a "link" in a relate field
  3163. } elseif (!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name) {
  3164. $temp_bean = BeanFactory::getBean($tar_rel_module, $rel_value['id_name']);
  3165. if ($temp_bean) {
  3166. $rel_list[] = $temp_bean;
  3167. return $rel_list;
  3168. }
  3169. }
  3170. }
  3171. // special case for unlisted parent-type relationships
  3172. if (!empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
  3173. $temp_bean = BeanFactory::getBean($tar_rel_module, $focus->parent_id);
  3174. if ($temp_bean) {
  3175. $rel_list[] = $temp_bean;
  3176. return $rel_list;
  3177. }
  3178. }
  3179. return $rel_list;
  3180. //end function search_filter_rel_info
  3181. }
  3182. function get_module_info($module_name)
  3183. {
  3184. global $beanList;
  3185. global $dictionary;
  3186. //Get dictionary and focus data for module
  3187. $vardef_name = $beanList[$module_name];
  3188. if ($vardef_name == 'aCase') {
  3189. $class_name = 'Case';
  3190. } else {
  3191. $class_name = $vardef_name;
  3192. }
  3193. if (!file_exists('modules/'.$module_name.'/'.$class_name.'.php')) {
  3194. return;
  3195. }
  3196. include_once 'modules/'.$module_name.'/'.$class_name.'.php';
  3197. $module_bean = new $vardef_name();
  3198. return $module_bean;
  3199. //end function get_module_table
  3200. }
  3201. /**
  3202. * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
  3203. *
  3204. * @param string $moduleName
  3205. */
  3206. function get_valid_bean_name($module_name)
  3207. {
  3208. global $beanList;
  3209. $vardef_name = $beanList[$module_name];
  3210. if ($vardef_name == 'aCase') {
  3211. $bean_name = 'Case';
  3212. } else {
  3213. $bean_name = $vardef_name;
  3214. }
  3215. return $bean_name;
  3216. }
  3217. function checkAuthUserStatus()
  3218. {
  3219. //authUserStatus();
  3220. }
  3221. /**
  3222. * This function returns an array of phpinfo() results that can be parsed and
  3223. * used to figure out what version we run, what modules are compiled in, etc.
  3224. *
  3225. * @param $level int info level constant (1,2,4,8...64);
  3226. *
  3227. * @return $returnInfo array array of info about the PHP environment
  3228. *
  3229. * @author original by "code at adspeed dot com" Fron php.net
  3230. * @author customized for Sugar by Chris N.
  3231. */
  3232. function getPhpInfo($level = -1)
  3233. {
  3234. /* Name (constant) Value Description
  3235. INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
  3236. INFO_CREDITS 2 PHP Credits. See also phpcredits().
  3237. INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
  3238. INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
  3239. INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
  3240. INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
  3241. INFO_LICENSE 64 PHP License information. See also the license FAQ.
  3242. INFO_ALL -1 Shows all of the above. This is the default value.
  3243. */
  3244. ob_start();
  3245. phpinfo($level);
  3246. $phpinfo = ob_get_contents();
  3247. ob_end_clean();
  3248. $phpinfo = strip_tags($phpinfo, '<h1><h2><th><td>');
  3249. $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/', '<info>\\1</info>', $phpinfo);
  3250. $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/', '<info>\\1</info>', $phpinfo);
  3251. $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
  3252. $match = '';
  3253. $version = '';
  3254. $returnInfo = array();
  3255. if (preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
  3256. $returnInfo['PHP Version'] = $version[1];
  3257. }
  3258. for ($i = 1; $i < count($parsedInfo); ++$i) {
  3259. if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
  3260. $vName = trim($match[1]);
  3261. $parsedInfo2 = explode("\n", $parsedInfo[$i + 1]);
  3262. foreach ($parsedInfo2 as $vOne) {
  3263. $vPat = '<info>([^<]+)<\/info>';
  3264. $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
  3265. $vPat2 = "/$vPat\s*$vPat/";
  3266. if (preg_match($vPat3, $vOne, $match)) { // 3cols
  3267. $returnInfo[$vName][trim($match[1])] = array(trim($match[2]), trim($match[3]));
  3268. } elseif (preg_match($vPat2, $vOne, $match)) { // 2cols
  3269. $returnInfo[$vName][trim($match[1])] = trim($match[2]);
  3270. }
  3271. }
  3272. } elseif (true) {
  3273. }
  3274. }
  3275. return $returnInfo;
  3276. }
  3277. /**
  3278. * This function will take a string that has tokens like {0}, {1} and will replace
  3279. * those tokens with the args provided.
  3280. *
  3281. * @param $format string to format
  3282. * @param $args args to replace
  3283. *
  3284. * @return $result a formatted string
  3285. */
  3286. function string_format($format, $args)
  3287. {
  3288. $result = $format;
  3289. /* Bug47277 fix.
  3290. * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
  3291. * IN () fails and IN ('') works.
  3292. */
  3293. if (count($args) == 1) {
  3294. reset($args);
  3295. $singleArgument = current($args);
  3296. if (empty($singleArgument)) {
  3297. return str_replace('{0}', "''", $result);
  3298. }
  3299. }
  3300. /* End of fix */
  3301. for ($i = 0; $i < count($args); ++$i) {
  3302. $result = str_replace('{'.$i.'}', $args[$i], $result);
  3303. }
  3304. return $result;
  3305. }
  3306. /**
  3307. * Generate a string for displaying a unique identifier that is composed
  3308. * of a system_id and number. This is use to allow us to generate quote
  3309. * numbers using a DB auto-increment key from offline clients and still
  3310. * have the number be unique (since it is modified by the system_id.
  3311. *
  3312. * @param $num of bean
  3313. * @param $system_id from system
  3314. *
  3315. * @return $result a formatted string
  3316. */
  3317. function format_number_display($num, $system_id)
  3318. {
  3319. global $sugar_config;
  3320. if (isset($num) && !empty($num)) {
  3321. $num = unformat_number($num);
  3322. if (isset($system_id) && $system_id == 1) {
  3323. return sprintf('%d', $num);
  3324. } else {
  3325. return sprintf('%d-%d', $num, $system_id);
  3326. }
  3327. }
  3328. }
  3329. function checkLoginUserStatus()
  3330. {
  3331. }
  3332. /**
  3333. * This function will take a number and system_id and format.
  3334. *
  3335. * @param $url URL containing host to append port
  3336. * @param $port the port number - if '' is passed, no change to url
  3337. *
  3338. * @return $resulturl the new URL with the port appended to the host
  3339. */
  3340. function appendPortToHost($url, $port)
  3341. {
  3342. $resulturl = $url;
  3343. // if no port, don't change the url
  3344. if ($port != '') {
  3345. $split = explode('/', $url);
  3346. //check if it starts with http, in case they didn't include that in url
  3347. if (str_begin($url, 'http')) {
  3348. //third index ($split[2]) will be the host
  3349. $split[2] .= ':'.$port;
  3350. } else {
  3351. // otherwise assumed to start with host name
  3352. //first index ($split[0]) will be the host
  3353. $split[0] .= ':'.$port;
  3354. }
  3355. $resulturl = implode('/', $split);
  3356. }
  3357. return $resulturl;
  3358. }
  3359. /**
  3360. * Singleton to return JSON object.
  3361. *
  3362. * @return JSON object
  3363. */
  3364. function getJSONobj()
  3365. {
  3366. static $json = null;
  3367. if (!isset($json)) {
  3368. require_once 'include/JSON.php';
  3369. $json = new JSON(JSON_LOOSE_TYPE);
  3370. }
  3371. return $json;
  3372. }
  3373. require_once 'include/utils/db_utils.php';
  3374. /**
  3375. * Set default php.ini settings for entry points.
  3376. */
  3377. function setPhpIniSettings()
  3378. {
  3379. // zlib module
  3380. // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
  3381. /*
  3382. if(function_exists('gzclose') && headers_sent() == false) {
  3383. ini_set('zlib.output_compression', 1);
  3384. }
  3385. */
  3386. // mbstring module
  3387. //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
  3388. /*if(function_exists('mb_strlen')) {
  3389. ini_set('mbstring.func_overload', 7);
  3390. ini_set('mbstring.internal_encoding', 'UTF-8');
  3391. }*/
  3392. // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
  3393. // starting with 5.2.0, backtrack_limit breaks JSON decoding
  3394. $backtrack_limit = ini_get('pcre.backtrack_limit');
  3395. if (!empty($backtrack_limit)) {
  3396. ini_set('pcre.backtrack_limit', '-1');
  3397. }
  3398. }
  3399. /**
  3400. * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
  3401. * language files. Language file merges do not need to account for null values so we can get some
  3402. * performance increases by using this specialized function. Note this merge function does not properly
  3403. * handle null values.
  3404. *
  3405. * @param $gimp
  3406. * @param $dom
  3407. *
  3408. * @return array
  3409. */
  3410. function sugarLangArrayMerge($gimp, $dom)
  3411. {
  3412. if (is_array($gimp) && is_array($dom)) {
  3413. foreach ($dom as $domKey => $domVal) {
  3414. if (isset($gimp[$domKey])) {
  3415. if (is_array($domVal)) {
  3416. $tempArr = array();
  3417. foreach ($domVal as $domArrKey => $domArrVal) {
  3418. $tempArr[$domArrKey] = $domArrVal;
  3419. }
  3420. foreach ($gimp[$domKey] as $gimpArrKey => $gimpArrVal) {
  3421. if (!isset($tempArr[$gimpArrKey])) {
  3422. $tempArr[$gimpArrKey] = $gimpArrVal;
  3423. }
  3424. }
  3425. $gimp[$domKey] = $tempArr;
  3426. } else {
  3427. $gimp[$domKey] = $domVal;
  3428. }
  3429. } else {
  3430. $gimp[$domKey] = $domVal;
  3431. }
  3432. }
  3433. } // if the passed value for gimp isn't an array, then return the $dom
  3434. elseif (is_array($dom)) {
  3435. return $dom;
  3436. }
  3437. return $gimp;
  3438. }
  3439. /**
  3440. * like array_merge() but will handle array elements that are themselves arrays;
  3441. * PHP's version just overwrites the element with the new one.
  3442. *
  3443. * @internal Note that this function deviates from the internal array_merge()
  3444. * functions in that it does does not treat numeric keys differently
  3445. * than string keys. Additionally, it deviates from
  3446. * array_merge_recursive() by not creating an array when like values
  3447. * found.
  3448. *
  3449. * @param array gimp the array whose values will be overloaded
  3450. * @param array dom the array whose values will pwn the gimp's
  3451. *
  3452. * @return array beaten gimp
  3453. */
  3454. function sugarArrayMerge($gimp, $dom)
  3455. {
  3456. if (is_array($gimp) && is_array($dom)) {
  3457. foreach ($dom as $domKey => $domVal) {
  3458. if (array_key_exists($domKey, $gimp)) {
  3459. if (is_array($domVal)) {
  3460. $tempArr = array();
  3461. foreach ($domVal as $domArrKey => $domArrVal) {
  3462. $tempArr[$domArrKey] = $domArrVal;
  3463. }
  3464. foreach ($gimp[$domKey] as $gimpArrKey => $gimpArrVal) {
  3465. if (!array_key_exists($gimpArrKey, $tempArr)) {
  3466. $tempArr[$gimpArrKey] = $gimpArrVal;
  3467. }
  3468. }
  3469. $gimp[$domKey] = $tempArr;
  3470. } else {
  3471. $gimp[$domKey] = $domVal;
  3472. }
  3473. } else {
  3474. $gimp[$domKey] = $domVal;
  3475. }
  3476. }
  3477. } // if the passed value for gimp isn't an array, then return the $dom
  3478. elseif (is_array($dom)) {
  3479. return $dom;
  3480. }
  3481. return $gimp;
  3482. }
  3483. /**
  3484. * Similiar to sugarArrayMerge except arrays of N depth are merged.
  3485. *
  3486. * @param array gimp the array whose values will be overloaded
  3487. * @param array dom the array whose values will pwn the gimp's
  3488. *
  3489. * @return array beaten gimp
  3490. */
  3491. function sugarArrayMergeRecursive($gimp, $dom)
  3492. {
  3493. if (is_array($gimp) && is_array($dom)) {
  3494. foreach ($dom as $domKey => $domVal) {
  3495. if (array_key_exists($domKey, $gimp)) {
  3496. if (is_array($domVal) && is_array($gimp[$domKey])) {
  3497. $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
  3498. } else {
  3499. $gimp[$domKey] = $domVal;
  3500. }
  3501. } else {
  3502. $gimp[$domKey] = $domVal;
  3503. }
  3504. }
  3505. } // if the passed value for gimp isn't an array, then return the $dom
  3506. elseif (is_array($dom)) {
  3507. return $dom;
  3508. }
  3509. return $gimp;
  3510. }
  3511. /**
  3512. * finds the correctly working versions of PHP-JSON.
  3513. *
  3514. * @return bool True if NOT found or WRONG version
  3515. */
  3516. function returnPhpJsonStatus()
  3517. {
  3518. if (function_exists('json_encode')) {
  3519. $phpInfo = getPhpInfo(8);
  3520. return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
  3521. }
  3522. return true; // not found
  3523. }
  3524. /**
  3525. * getTrackerSubstring.
  3526. *
  3527. * Returns a [number]-char or less string for the Tracker to display in the header
  3528. * based on the tracker_max_display_length setting in config.php. If not set,
  3529. * or invalid length, then defaults to 15 for COM editions, 30 for others.
  3530. *
  3531. * @param string name field for a given Object
  3532. *
  3533. * @return string [number]-char formatted string if length of string exceeds the max allowed
  3534. */
  3535. function getTrackerSubstring($name)
  3536. {
  3537. static $max_tracker_item_length;
  3538. //Trim the name
  3539. $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
  3540. $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
  3541. global $sugar_config;
  3542. if (!isset($max_tracker_item_length)) {
  3543. if (isset($sugar_config['tracker_max_display_length'])) {
  3544. $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;
  3545. } else {
  3546. $max_tracker_item_length = 15;
  3547. }
  3548. }
  3549. if ($strlen > $max_tracker_item_length) {
  3550. $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length - 3, 'UTF-8') : substr($name, 0, $max_tracker_item_length - 3);
  3551. $chopped .= '...';
  3552. } else {
  3553. $chopped = $name;
  3554. }
  3555. return $chopped;
  3556. }
  3557. function generate_search_where($field_list = array(), $values = array(), &$bean, $add_custom_fields = false, $module = '')
  3558. {
  3559. $where_clauses = array();
  3560. $like_char = '%';
  3561. $table_name = $bean->object_name;
  3562. foreach ($field_list[$module] as $field => $parms) {
  3563. if (isset($values[$field]) && $values[$field] != '') {
  3564. $operator = 'like';
  3565. if (!empty($parms['operator'])) {
  3566. $operator = $parms['operator'];
  3567. }
  3568. if (is_array($values[$field])) {
  3569. $operator = 'in';
  3570. $field_value = '';
  3571. foreach ($values[$field] as $key => $val) {
  3572. if ($val != ' ' and $val != '') {
  3573. if (!empty($field_value)) {
  3574. $field_value .= ',';
  3575. }
  3576. $field_value .= "'".$GLOBALS['db']->quote($val)."'";
  3577. }
  3578. }
  3579. } else {
  3580. $field_value = $GLOBALS['db']->quote($values[$field]);
  3581. }
  3582. //set db_fields array.
  3583. if (!isset($parms['db_field'])) {
  3584. $parms['db_field'] = array($field);
  3585. }
  3586. if (isset($parms['my_items']) and $parms['my_items'] == true) {
  3587. global $current_user;
  3588. $field_value = $GLOBALS['db']->quote($current_user->id);
  3589. $operator = '=';
  3590. }
  3591. $where = '';
  3592. $itr = 0;
  3593. if ($field_value != '') {
  3594. foreach ($parms['db_field'] as $db_field) {
  3595. if (strstr($db_field, '.') === false) {
  3596. $db_field = $bean->table_name.'.'.$db_field;
  3597. }
  3598. if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type'] == 'case_insensitive') {
  3599. $db_field = 'upper('.$db_field.')';
  3600. $field_value = strtoupper($field_value);
  3601. }
  3602. ++$itr;
  3603. if (!empty($where)) {
  3604. $where .= ' OR ';
  3605. }
  3606. switch (strtolower($operator)) {
  3607. case 'like' :
  3608. $where .= $db_field." like '".$field_value.$like_char."'";
  3609. break;
  3610. case 'in':
  3611. $where .= $db_field.' in ('.$field_value.')';
  3612. break;
  3613. case '=':
  3614. $where .= $db_field." = '".$field_value."'";
  3615. break;
  3616. }
  3617. }
  3618. }
  3619. if (!empty($where)) {
  3620. if ($itr > 1) {
  3621. array_push($where_clauses, '( '.$where.' )');
  3622. } else {
  3623. array_push($where_clauses, $where);
  3624. }
  3625. }
  3626. }
  3627. }
  3628. if ($add_custom_fields) {
  3629. require_once 'modules/DynamicFields/DynamicField.php';
  3630. $bean->setupCustomFields($module);
  3631. $bean->custom_fields->setWhereClauses($where_clauses);
  3632. }
  3633. return $where_clauses;
  3634. }
  3635. function add_quotes($str)
  3636. {
  3637. return "'{$str}'";
  3638. }
  3639. /**
  3640. * This function will rebuild the config file.
  3641. *
  3642. * @param $sugar_config
  3643. * @param $sugar_version
  3644. *
  3645. * @return bool true if successful
  3646. */
  3647. function rebuildConfigFile($sugar_config, $sugar_version)
  3648. {
  3649. // add defaults to missing values of in-memory sugar_config
  3650. $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config);
  3651. // need to override version with default no matter what
  3652. $sugar_config['sugar_version'] = $sugar_version;
  3653. ksort($sugar_config);
  3654. if (write_array_to_file('sugar_config', $sugar_config, 'config.php')) {
  3655. return true;
  3656. } else {
  3657. return false;
  3658. }
  3659. }
  3660. /**
  3661. * Loads clean configuration, not overridden by config_override.php.
  3662. *
  3663. * @return array
  3664. */
  3665. function loadCleanConfig()
  3666. {
  3667. $sugar_config = array();
  3668. require 'config.php';
  3669. return $sugar_config;
  3670. }
  3671. /**
  3672. * getJavascriptSiteURL
  3673. * This function returns a URL for the client javascript calls to access
  3674. * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
  3675. * are used to access the site. Thus, the hostname in the URL returned may
  3676. * not always match that of $sugar_config['site_url']. Basically, the
  3677. * assumption is that however the user accessed the website is how they
  3678. * will continue to with subsequent javascript requests. If the variable
  3679. * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
  3680. *
  3681. * @return $site_url The url used to refer to the website
  3682. */
  3683. function getJavascriptSiteURL()
  3684. {
  3685. global $sugar_config;
  3686. if (!empty($_SERVER['HTTP_REFERER'])) {
  3687. $url = parse_url($_SERVER['HTTP_REFERER']);
  3688. $replacement_url = $url['scheme'].'://'.$url['host'];
  3689. if (!empty($url['port'])) {
  3690. $replacement_url .= ':'.$url['port'];
  3691. }
  3692. $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/', $replacement_url, $sugar_config['site_url']);
  3693. } else {
  3694. $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/', 'http$1://'.$_SERVER['HTTP_HOST'], $sugar_config['site_url']);
  3695. if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443') {
  3696. $site_url = preg_replace('/^http\:/', 'https:', $site_url);
  3697. }
  3698. }
  3699. $GLOBALS['log']->debug('getJavascriptSiteURL(), site_url='.$site_url);
  3700. return $site_url;
  3701. }
  3702. // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
  3703. function add_squotes($str)
  3704. {
  3705. return "'".$str."'";
  3706. }
  3707. // recursive function to count the number of levels within an array
  3708. function array_depth($array, $depth_count = -1, $depth_array = array())
  3709. {
  3710. ++$depth_count;
  3711. if (is_array($array)) {
  3712. foreach ($array as $key => $value) {
  3713. $depth_array[] = array_depth($value, $depth_count);
  3714. }
  3715. } else {
  3716. return $depth_count;
  3717. }
  3718. foreach ($depth_array as $value) {
  3719. $depth_count = $value > $depth_count ? $value : $depth_count;
  3720. }
  3721. return $depth_count;
  3722. }
  3723. /**
  3724. * Creates a new Group User.
  3725. *
  3726. * @param string $name Name of Group User
  3727. *
  3728. * @return string GUID of new Group User
  3729. */
  3730. function createGroupUser($name)
  3731. {
  3732. $group = new User();
  3733. $group->user_name = $name;
  3734. $group->last_name = $name;
  3735. $group->is_group = 1;
  3736. $group->deleted = 0;
  3737. $group->status = 'Active'; // cn: bug 6711
  3738. $group->setPreference('timezone', TimeDate::userTimezone());
  3739. $group->save();
  3740. return $group->id;
  3741. }
  3742. /*
  3743. * Helper function to locate an icon file given only a name
  3744. * Searches through the various paths for the file
  3745. * @param string iconFileName The filename of the icon
  3746. * @return string Relative pathname of the located icon, or '' if not found
  3747. */
  3748. function _getIcon($iconFileName)
  3749. {
  3750. $iconName = "icon_{$iconFileName}.gif";
  3751. $iconFound = SugarThemeRegistry::current()->getImageURL($iconName, false);
  3752. //First try un-ucfirst-ing the icon name
  3753. if (empty($iconFound)) {
  3754. $iconName = 'icon_'.strtolower(substr($iconFileName, 0, 1)).substr($iconFileName, 1).'.gif';
  3755. }
  3756. $iconFound = SugarThemeRegistry::current()->getImageURL($iconName, false);
  3757. //Next try removing the icon prefix
  3758. if (empty($iconFound)) {
  3759. $iconName = "{$iconFileName}.gif";
  3760. }
  3761. $iconFound = SugarThemeRegistry::current()->getImageURL($iconName, false);
  3762. if (empty($iconFound)) {
  3763. $iconName = '';
  3764. }
  3765. return $iconName;
  3766. }
  3767. /**
  3768. * Function to grab the correct icon image for Studio.
  3769. *
  3770. * @param string $iconFileName Name of the icon file
  3771. * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
  3772. * @param string $width Width of image
  3773. * @param string $height Height of image
  3774. * @param string $align Alignment of image
  3775. * @param string $alt Alt tag of image
  3776. *
  3777. * @return string $string <img> tag with corresponding image
  3778. */
  3779. function getStudioIcon($iconFileName = '', $altFileName = '', $width = '48', $height = '48', $align = 'baseline', $alt = '')
  3780. {
  3781. global $app_strings, $theme;
  3782. $iconName = _getIcon($iconFileName);
  3783. if (empty($iconName)) {
  3784. $iconName = _getIcon($altFileName);
  3785. if (empty($iconName)) {
  3786. return $app_strings['LBL_NO_IMAGE'];
  3787. }
  3788. }
  3789. return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
  3790. }
  3791. /**
  3792. * Function to grab the correct icon image for Dashlets Dialog.
  3793. *
  3794. * @param string $filename Location of the icon file
  3795. * @param string $module Name of the module to fall back onto if file does not exist
  3796. * @param string $width Width of image
  3797. * @param string $height Height of image
  3798. * @param string $align Alignment of image
  3799. * @param string $alt Alt tag of image
  3800. *
  3801. * @return string $string <img> tag with corresponding image
  3802. */
  3803. function get_dashlets_dialog_icon($module = '', $width = '32', $height = '32', $align = 'absmiddle', $alt = '')
  3804. {
  3805. global $app_strings, $theme;
  3806. $iconName = _getIcon($module.'_32');
  3807. if (empty($iconName)) {
  3808. $iconName = _getIcon($module);
  3809. }
  3810. if (empty($iconName)) {
  3811. return $app_strings['LBL_NO_IMAGE'];
  3812. }
  3813. return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
  3814. }
  3815. // works nicely to change UTF8 strings that are html entities - good for PDF conversions
  3816. function html_entity_decode_utf8($string)
  3817. {
  3818. static $trans_tbl;
  3819. // replace numeric entities
  3820. //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
  3821. $string = preg_replace_callback('~&#x0*([0-9a-f]+);~i',
  3822. function($matches) {
  3823. return code2utf(hexdec($matches[1]));
  3824. }, $string);
  3825. $string = preg_replace_callback('~&#0*([0-9]+);~',
  3826. function($matches) {
  3827. return code2utf($matches[1]);
  3828. }, $string);
  3829. // replace literal entities
  3830. if (!isset($trans_tbl)) {
  3831. $trans_tbl = array();
  3832. foreach (get_html_translation_table(HTML_ENTITIES) as $val => $key) {
  3833. $trans_tbl[$key] = utf8_encode($val);
  3834. }
  3835. }
  3836. return strtr($string, $trans_tbl);
  3837. }
  3838. // Returns the utf string corresponding to the unicode value
  3839. function code2utf($num)
  3840. {
  3841. if ($num < 128) {
  3842. return chr($num);
  3843. }
  3844. if ($num < 2048) {
  3845. return chr(($num >> 6) + 192).chr(($num & 63) + 128);
  3846. }
  3847. if ($num < 65536) {
  3848. return chr(($num >> 12) + 224).chr((($num >> 6) & 63) + 128).chr(($num & 63) + 128);
  3849. }
  3850. if ($num < 2097152) {
  3851. return chr(($num >> 18) + 240).chr((($num >> 12) & 63) + 128).chr((($num >> 6) & 63) + 128).chr(($num & 63) + 128);
  3852. }
  3853. return '';
  3854. }
  3855. function str_split_php4($string, $length = 1)
  3856. {
  3857. $string_length = strlen($string);
  3858. $return = array();
  3859. $cursor = 0;
  3860. if ($length > $string_length) {
  3861. // use the string_length as the string is shorter than the length
  3862. $length = $string_length;
  3863. }
  3864. for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
  3865. $return[] = substr($string, $cursor, $length);
  3866. }
  3867. return $return;
  3868. }
  3869. if (version_compare(phpversion(), '5.0.0', '<')) {
  3870. function str_split($string, $length = 1)
  3871. {
  3872. return str_split_php4($string, $length);
  3873. }
  3874. }
  3875. /*
  3876. * @deprecated use DBManagerFactory::isFreeTDS
  3877. */
  3878. function is_freetds()
  3879. {
  3880. return DBManagerFactory::isFreeTDS();
  3881. }
  3882. /**
  3883. * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
  3884. *
  3885. * @todo this won't work completely right until we impliment css compression and combination
  3886. * for now, we'll just include the last css file found.
  3887. *
  3888. * @return chart.css file to use
  3889. */
  3890. function chartStyle()
  3891. {
  3892. return SugarThemeRegistry::current()->getCSSURL('chart.css');
  3893. }
  3894. /**
  3895. * Chart dashlet helper functions that returns the correct XML color file for charts,
  3896. * dependent on the current theme.
  3897. *
  3898. * @return sugarColors.xml to use
  3899. */
  3900. function chartColors()
  3901. {
  3902. if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml') == '') {
  3903. return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
  3904. }
  3905. return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
  3906. }
  3907. /* End Chart Dashlet helper functions */
  3908. /**
  3909. * This function is designed to set up the php enviroment
  3910. * for AJAX requests.
  3911. */
  3912. function ajaxInit()
  3913. {
  3914. ini_set('display_errors', 'false');
  3915. }
  3916. /**
  3917. * Returns an absolute path from the given path, determining if it is relative or absolute.
  3918. *
  3919. * @param string $path
  3920. *
  3921. * @return string
  3922. */
  3923. function getAbsolutePath(
  3924. $path,
  3925. $currentServer = false
  3926. ) {
  3927. $path = trim($path);
  3928. // try to match absolute paths like \\server\share, /directory or c:\
  3929. if ((substr($path, 0, 2) == '\\\\')
  3930. || ($path[0] == '/')
  3931. || preg_match('/^[A-z]:/i', $path)
  3932. || $currentServer
  3933. ) {
  3934. return $path;
  3935. }
  3936. return getcwd().'/'.$path;
  3937. }
  3938. /**
  3939. * Returns the bean object of the given module.
  3940. *
  3941. * @deprecated use SugarModule::loadBean() instead
  3942. *
  3943. * @param string $module
  3944. *
  3945. * @return object
  3946. */
  3947. function loadBean(
  3948. $module
  3949. ) {
  3950. return SugarModule::get($module)->loadBean();
  3951. }
  3952. /**
  3953. * Returns true if the application is being accessed on a touch screen interface ( like an iPad ).
  3954. */
  3955. function isTouchScreen()
  3956. {
  3957. $ua = empty($_SERVER['HTTP_USER_AGENT']) ? 'undefined' : strtolower($_SERVER['HTTP_USER_AGENT']);
  3958. // first check if we have forced use of the touch enhanced interface
  3959. if (isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1') {
  3960. return true;
  3961. }
  3962. // next check if we should use the touch interface with our device
  3963. if (strpos($ua, 'ipad') !== false) {
  3964. return true;
  3965. }
  3966. return false;
  3967. }
  3968. /**
  3969. * Returns the shortcut keys to access the shortcut links. Shortcut
  3970. * keys vary depending on browser versions and operating systems.
  3971. *
  3972. * @return string value of the shortcut keys
  3973. */
  3974. function get_alt_hot_key()
  3975. {
  3976. $ua = '';
  3977. if (isset($_SERVER['HTTP_USER_AGENT'])) {
  3978. $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
  3979. }
  3980. $isMac = strpos($ua, 'mac') !== false;
  3981. $isLinux = strpos($ua, 'linux') !== false;
  3982. if (!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
  3983. if (preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
  3984. return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
  3985. }
  3986. }
  3987. return $isMac ? 'Ctrl+' : 'Alt+';
  3988. }
  3989. function can_start_session()
  3990. {
  3991. if (!empty($_GET['PHPSESSID'])) {
  3992. return true;
  3993. }
  3994. $session_id = session_id();
  3995. return empty($session_id) ? true : false;
  3996. }
  3997. function load_link_class($properties)
  3998. {
  3999. $class = 'Link2';
  4000. if (!empty($properties['link_class']) && !empty($properties['link_file'])) {
  4001. require_once $properties['link_file'];
  4002. $class = $properties['link_class'];
  4003. }
  4004. return $class;
  4005. }
  4006. function inDeveloperMode()
  4007. {
  4008. return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
  4009. }
  4010. /**
  4011. * Filter the protocol list for inbound email accounts.
  4012. *
  4013. * @param array $protocol
  4014. */
  4015. function filterInboundEmailPopSelection($protocol)
  4016. {
  4017. if (!isset($GLOBALS['sugar_config']['allow_pop_inbound']) || !$GLOBALS['sugar_config']['allow_pop_inbound']) {
  4018. if (isset($protocol['pop3'])) {
  4019. unset($protocol['pop3']);
  4020. }
  4021. } else {
  4022. $protocol['pop3'] = 'POP3';
  4023. }
  4024. return $protocol;
  4025. }
  4026. /**
  4027. * The function is used because currently we are not supporting mbstring.func_overload
  4028. * 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.
  4029. * 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.
  4030. *
  4031. * @returns the substred strings.
  4032. */
  4033. function sugar_substr($string, $length, $charset = 'UTF-8')
  4034. {
  4035. if (mb_strlen($string, $charset) > $length) {
  4036. $string = trim(mb_substr(trim($string), 0, $length, $charset));
  4037. }
  4038. return $string;
  4039. }
  4040. /**
  4041. * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
  4042. * This will work even without setting the mbstring.*encoding.
  4043. */
  4044. function sugar_ucfirst($string, $charset = 'UTF-8')
  4045. {
  4046. return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_substr($string, 1, mb_strlen($string), $charset);
  4047. }
  4048. /**
  4049. *
  4050. */
  4051. function unencodeMultienum($string)
  4052. {
  4053. if (is_array($string)) {
  4054. return $string;
  4055. }
  4056. if (substr($string, 0, 1) == '^' && substr($string, -1) == '^') {
  4057. $string = substr(substr($string, 1), 0, strlen($string) - 2);
  4058. }
  4059. return explode('^,^', $string);
  4060. }
  4061. function encodeMultienumValue($arr)
  4062. {
  4063. if (!is_array($arr)) {
  4064. return $arr;
  4065. }
  4066. if (empty($arr)) {
  4067. return '';
  4068. }
  4069. $string = '^'.implode('^,^', $arr).'^';
  4070. return $string;
  4071. }
  4072. /**
  4073. * create_export_query is used for export and massupdate
  4074. * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
  4075. * This function will correct the where clause and output necessary join condition for them.
  4076. *
  4077. * @param $module : the module name
  4078. * @param $searchFields : searchFields which is got after $searchForm->populateFromArray()
  4079. * @param $where : where clauses
  4080. *
  4081. * @return array
  4082. */
  4083. function create_export_query_relate_link_patch($module, $searchFields, $where)
  4084. {
  4085. if (file_exists('modules/'.$module.'/SearchForm.html')) {
  4086. $ret_array['where'] = $where;
  4087. return $ret_array;
  4088. }
  4089. $seed = BeanFactory::getBean($module);
  4090. foreach ($seed->field_defs as $name => $field) {
  4091. if ($field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value'])) {
  4092. $seed->load_relationship($field['link']);
  4093. $params = array();
  4094. if (empty($join_type)) {
  4095. $params['join_type'] = ' LEFT JOIN ';
  4096. } else {
  4097. $params['join_type'] = $join_type;
  4098. }
  4099. if (isset($data['join_name'])) {
  4100. $params['join_table_alias'] = $field['join_name'];
  4101. } else {
  4102. $params['join_table_alias'] = 'join_'.$field['name'];
  4103. }
  4104. if (isset($data['join_link_name'])) {
  4105. $params['join_table_link_alias'] = $field['join_link_name'];
  4106. } else {
  4107. $params['join_table_link_alias'] = 'join_link_'.$field['name'];
  4108. }
  4109. $fieldLink = $field['link'];
  4110. $join = $seed->$fieldLink->getJoin($params, true);
  4111. $join_table_alias = 'join_'.$field['name'];
  4112. if (isset($field['db_concat_fields'])) {
  4113. $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
  4114. $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
  4115. } else {
  4116. $where = preg_replace('/(^|[\s(])'.$field['name'].'/', '${1}'.$join_table_alias.'.'.$field['rname'], $where);
  4117. }
  4118. }
  4119. }
  4120. $ret_array = array('where' => $where, 'join' => isset($join['join']) ? $join['join'] : '');
  4121. return $ret_array;
  4122. }
  4123. /**
  4124. * 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.
  4125. *
  4126. * @Depends on QuickRepairAndRebuild.php
  4127. * @Relate bug 30642 ,23177
  4128. */
  4129. function clearAllJsAndJsLangFilesWithoutOutput()
  4130. {
  4131. global $current_language, $mod_strings;
  4132. $MBmodStrings = $mod_strings;
  4133. $mod_strings = return_module_language($current_language, 'Administration');
  4134. include_once 'modules/Administration/QuickRepairAndRebuild.php';
  4135. $repair = new RepairAndClear();
  4136. $repair->module_list = array();
  4137. $repair->show_output = false;
  4138. $repair->clearJsLangFiles();
  4139. $repair->clearJsFiles();
  4140. $mod_strings = $MBmodStrings;
  4141. }
  4142. /**
  4143. * This function will allow you to get a variable value from query string.
  4144. */
  4145. function getVariableFromQueryString($variable, $string)
  4146. {
  4147. $matches = array();
  4148. $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
  4149. if ($number) {
  4150. return $matches[1];
  4151. } else {
  4152. return false;
  4153. }
  4154. }
  4155. /**
  4156. * should_hide_iframes
  4157. * This is a helper method to determine whether or not to show iframes (My Sites) related
  4158. * information in the application.
  4159. *
  4160. * @return bool flag indicating whether or not iframes module should be hidden
  4161. */
  4162. function should_hide_iframes()
  4163. {
  4164. //Remove the MySites module
  4165. if (file_exists('modules/iFrames/iFrame.php')) {
  4166. if (!class_exists('iFrame')) {
  4167. require_once 'modules/iFrames/iFrame.php';
  4168. }
  4169. return false;
  4170. }
  4171. return true;
  4172. }
  4173. /**
  4174. * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA.
  4175. *
  4176. * @param string $version
  4177. *
  4178. * @return string RC, BETA, GA
  4179. */
  4180. function getVersionStatus($version)
  4181. {
  4182. if (preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
  4183. return strtoupper($matches[1]);
  4184. } else {
  4185. return 'GA';
  4186. }
  4187. }
  4188. /**
  4189. * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
  4190. * 5.5.1RC1 then return 5.5.1.
  4191. *
  4192. * @param string $version
  4193. *
  4194. * @return version
  4195. */
  4196. function getMajorMinorVersion($version)
  4197. {
  4198. if (preg_match('/^([\d\.]+).*$/si', $version, $matches2)) {
  4199. $version = $matches2[1];
  4200. $arr = explode('.', $version);
  4201. if (count($arr) > 2) {
  4202. if ($arr[2] == '0') {
  4203. $version = substr($version, 0, 3);
  4204. }
  4205. }
  4206. }
  4207. return $version;
  4208. }
  4209. /**
  4210. * Return string composed of seconds & microseconds of current time, without dots.
  4211. *
  4212. * @return string
  4213. */
  4214. function sugar_microtime()
  4215. {
  4216. $now = explode(' ', microtime());
  4217. $unique_id = $now[1].str_replace('.', '', $now[0]);
  4218. return $unique_id;
  4219. }
  4220. /**
  4221. * Extract urls from a piece of text.
  4222. *
  4223. * @param $string
  4224. *
  4225. * @return array of urls found in $string
  4226. */
  4227. function getUrls($string)
  4228. {
  4229. $lines = explode('<br>', trim($string));
  4230. $urls = array();
  4231. foreach ($lines as $line) {
  4232. $regex = '/http?\:\/\/[^\" ]+/i';
  4233. preg_match_all($regex, $line, $matches);
  4234. foreach ($matches[0] as $match) {
  4235. $urls[] = $match;
  4236. }
  4237. }
  4238. return $urls;
  4239. }
  4240. /**
  4241. * Sanitize image file from hostile content.
  4242. *
  4243. * @param string $path Image file
  4244. * @param bool $jpeg Accept only JPEGs?
  4245. */
  4246. function verify_image_file($path, $jpeg = false)
  4247. {
  4248. if (function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
  4249. $img = imagecreatefromstring(file_get_contents($path));
  4250. if (!$img) {
  4251. return false;
  4252. }
  4253. $img_size = getimagesize($path);
  4254. $filetype = $img_size['mime'];
  4255. //if filetype is jpeg or if we are only allowing jpegs, create jpg image
  4256. if ($filetype == 'image/jpeg' || $jpeg) {
  4257. ob_start();
  4258. imagejpeg($img);
  4259. $image = ob_get_clean();
  4260. // not writing directly because imagejpeg does not work with streams
  4261. if (file_put_contents($path, $image)) {
  4262. return true;
  4263. }
  4264. } elseif ($filetype == 'image/png') {
  4265. // else if the filetype is png, create png
  4266. imagealphablending($img, true);
  4267. imagesavealpha($img, true);
  4268. ob_start();
  4269. imagepng($img);
  4270. $image = ob_get_clean();
  4271. if (file_put_contents($path, $image)) {
  4272. return true;
  4273. }
  4274. } else {
  4275. return false;
  4276. }
  4277. } else {
  4278. // check image manually
  4279. $fp = fopen($path, 'rb');
  4280. if (!$fp) {
  4281. return false;
  4282. }
  4283. $data = '';
  4284. // read the whole file in chunks
  4285. while (!feof($fp)) {
  4286. $data .= fread($fp, 8192);
  4287. }
  4288. fclose($fp);
  4289. if (preg_match("/<(\?php|html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
  4290. $data, $m)) {
  4291. $GLOBALS['log']->fatal("Found {$m[0]} in $path, not allowing upload");
  4292. return false;
  4293. }
  4294. return true;
  4295. }
  4296. return false;
  4297. }
  4298. /**
  4299. * Verify uploaded image
  4300. * Verifies that image has proper extension, MIME type and doesn't contain hostile content.
  4301. *
  4302. * @param string $path Image path
  4303. * @param bool $jpeg_only Accept only JPEGs?
  4304. */
  4305. function verify_uploaded_image($path, $jpeg_only = false)
  4306. {
  4307. $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
  4308. if (!$jpeg_only) {
  4309. $supportedExtensions['png'] = 'image/png';
  4310. }
  4311. if (!file_exists($path) || !is_file($path)) {
  4312. return false;
  4313. }
  4314. $img_size = getimagesize($path);
  4315. $filetype = $img_size['mime'];
  4316. $tmpArray = explode('.', $path);
  4317. $ext = end($tmpArray);
  4318. if (substr_count('..', $path) > 0 || ($ext !== $path && !isset($supportedExtensions[strtolower($ext)])) ||
  4319. !in_array($filetype, array_values($supportedExtensions))
  4320. ) {
  4321. return false;
  4322. }
  4323. return verify_image_file($path, $jpeg_only);
  4324. }
  4325. function cmp_beans($a, $b)
  4326. {
  4327. global $sugar_web_service_order_by;
  4328. //If the order_by field is not valid, return 0;
  4329. if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)) {
  4330. return 0;
  4331. }
  4332. if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
  4333. || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by)
  4334. ) {
  4335. return 0;
  4336. }
  4337. if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by) {
  4338. return -1;
  4339. } else {
  4340. return 1;
  4341. }
  4342. }
  4343. function order_beans($beans, $field_name)
  4344. {
  4345. //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
  4346. global $sugar_web_service_order_by;
  4347. $sugar_web_service_order_by = $field_name;
  4348. usort($beans, 'cmp_beans');
  4349. return $beans;
  4350. }
  4351. /**
  4352. * Return search like string
  4353. * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
  4354. *
  4355. * @param string $str string to be searched
  4356. * @param string $like_char Database like character, usually '%'
  4357. *
  4358. * @return string Returns a string to be searched in db query
  4359. */
  4360. function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true)
  4361. {
  4362. // override default wildcard character
  4363. if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
  4364. strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1
  4365. ) {
  4366. $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
  4367. }
  4368. // add wildcard at the beginning of the search string
  4369. if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
  4370. $GLOBALS['sugar_config']['search_wildcard_infront'] == true
  4371. ) {
  4372. if (substr($str, 0, 1) != $wildcard) {
  4373. $str = $wildcard.$str;
  4374. }
  4375. }
  4376. // add wildcard at the end of search string (default)
  4377. if ($appendWildcard) {
  4378. if (substr($str, -1) != $wildcard) {
  4379. $str .= $wildcard;
  4380. }
  4381. }
  4382. return str_replace($wildcard, $like_char, $str);
  4383. }
  4384. //check to see if custom utils exists
  4385. if (file_exists('custom/include/custom_utils.php')) {
  4386. include_once 'custom/include/custom_utils.php';
  4387. }
  4388. //check to see if custom utils exists in Extension framework
  4389. if (file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
  4390. include_once 'custom/application/Ext/Utils/custom_utils.ext.php';
  4391. }
  4392. /**
  4393. * @param $input - the input string to sanitize
  4394. * @param int $quotes - use quotes
  4395. * @param string $charset - the default charset
  4396. * @param bool $remove - strip tags or not
  4397. *
  4398. * @return string - the sanitized string
  4399. */
  4400. function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
  4401. {
  4402. return htmlentities($input, $quotes, $charset);
  4403. }
  4404. /**
  4405. * @return string - the full text search engine name
  4406. */
  4407. function getFTSEngineType()
  4408. {
  4409. if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
  4410. foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
  4411. return $name;
  4412. }
  4413. }
  4414. return '';
  4415. }
  4416. /**
  4417. * @param string $optionName - name of the option to be retrieved from app_list_strings
  4418. *
  4419. * @return array - the array to be used in option element
  4420. */
  4421. function getFTSBoostOptions($optionName)
  4422. {
  4423. if (isset($GLOBALS['app_list_strings'][$optionName])) {
  4424. return $GLOBALS['app_list_strings'][$optionName];
  4425. } else {
  4426. return array();
  4427. }
  4428. }
  4429. /**
  4430. * utf8_recursive_encode.
  4431. *
  4432. * This function walks through an Array and recursively calls utf8_encode on the
  4433. * values of each of the elements.
  4434. *
  4435. * @param $data Array of data to encode
  4436. *
  4437. * @return utf8 encoded Array data
  4438. */
  4439. function utf8_recursive_encode($data)
  4440. {
  4441. $result = array();
  4442. foreach ($data as $key => $val) {
  4443. if (is_array($val)) {
  4444. $result[$key] = utf8_recursive_encode($val);
  4445. } else {
  4446. $result[$key] = utf8_encode($val);
  4447. }
  4448. }
  4449. return $result;
  4450. }
  4451. /**
  4452. * get_language_header.
  4453. *
  4454. * This is a utility function for 508 Compliance. It returns the lang=[Current Language] text string used
  4455. * inside the <html> tag. If no current language is specified, it defaults to lang='en'.
  4456. *
  4457. * @return string The lang=[Current Language] markup to insert into the <html> tag
  4458. */
  4459. function get_language_header()
  4460. {
  4461. return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
  4462. }
  4463. /**
  4464. * get_custom_file_if_exists.
  4465. *
  4466. * This function handles the repetitive code we have where we first check if a file exists in the
  4467. * custom directory to determine whether we should load it, require it, include it, etc. This function returns the
  4468. * path of the custom file if it exists. It basically checks if custom/{$file} exists and returns this path if so;
  4469. * otherwise it return $file
  4470. *
  4471. * @param $file String of filename to check
  4472. *
  4473. * @return $file String of filename including custom directory if found
  4474. */
  4475. function get_custom_file_if_exists($file)
  4476. {
  4477. return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
  4478. }
  4479. /**
  4480. * get_help_url.
  4481. *
  4482. * This will return the URL used to redirect the user to the help documentation.
  4483. * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
  4484. * in config.php or config_override.php.
  4485. *
  4486. * @param string $send_edition
  4487. * @param string $send_version
  4488. * @param string $send_lang
  4489. * @param string $send_module
  4490. * @param string $send_action
  4491. * @param string $dev_status
  4492. * @param string $send_key
  4493. * @param string $send_anchor
  4494. *
  4495. * @return string the completed help URL
  4496. */
  4497. function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '')
  4498. {
  4499. global $sugar_config;
  4500. if (!empty($sugar_config['custom_help_url'])) {
  4501. $sendUrl = $sugar_config['custom_help_url'];
  4502. } else {
  4503. if (!empty($sugar_config['custom_help_base_url'])) {
  4504. $baseUrl = $sugar_config['custom_help_base_url'];
  4505. } else {
  4506. $baseUrl = 'http://www.sugarcrm.com/crm/product_doc.php';
  4507. }
  4508. $sendUrl = $baseUrl."?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
  4509. if (!empty($send_anchor)) {
  4510. $sendUrl .= '&anchor='.$send_anchor;
  4511. }
  4512. }
  4513. return $sendUrl;
  4514. }
  4515. /**
  4516. * generateETagHeader.
  4517. *
  4518. * This function generates the necessary cache headers for using ETags with dynamic content. You
  4519. * simply have to generate the ETag, pass it in, and the function handles the rest.
  4520. *
  4521. * @param string $etag ETag to use for this content.
  4522. */
  4523. function generateETagHeader($etag)
  4524. {
  4525. header('cache-control:');
  4526. header('Expires: ');
  4527. header('ETag: '.$etag);
  4528. header('Pragma:');
  4529. if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
  4530. if ($etag == $_SERVER['HTTP_IF_NONE_MATCH']) {
  4531. ob_clean();
  4532. header('Status: 304 Not Modified');
  4533. header('HTTP/1.0 304 Not Modified');
  4534. die();
  4535. }
  4536. }
  4537. }
  4538. /**
  4539. * getReportNameTranslation.
  4540. *
  4541. * Translates the report name if a translation exists,
  4542. * otherwise just returns the name
  4543. *
  4544. * @param string $reportName
  4545. *
  4546. * @return string translated report name
  4547. */
  4548. function getReportNameTranslation($reportName)
  4549. {
  4550. global $current_language;
  4551. // Used for translating reports
  4552. $mod_strings = return_module_language($current_language, 'Reports');
  4553. // Search for the report name in the default language and get the key
  4554. $key = array_search($reportName, return_module_language('', 'Reports'));
  4555. // If the key was found, use it to get a translation, otherwise just use report name
  4556. if (!empty($key)) {
  4557. $title = $mod_strings[$key];
  4558. } else {
  4559. $title = $reportName;
  4560. }
  4561. return $title;
  4562. }
  4563. /**
  4564. * Remove vars marked senstitive from array.
  4565. *
  4566. * @param array $defs
  4567. * @param SugarBean|array $data
  4568. *
  4569. * @return mixed $data without sensitive fields
  4570. */
  4571. function clean_sensitive_data($defs, $data)
  4572. {
  4573. foreach ($defs as $field => $def) {
  4574. if (!empty($def['sensitive'])) {
  4575. if (is_array($data)) {
  4576. $data[$field] = '';
  4577. }
  4578. if ($data instanceof SugarBean) {
  4579. $data->$field = '';
  4580. }
  4581. }
  4582. }
  4583. return $data;
  4584. }
  4585. /**
  4586. * Return relations with labels for duplicates.
  4587. */
  4588. function getDuplicateRelationListWithTitle($def, $var_def, $module)
  4589. {
  4590. global $current_language;
  4591. $select_array = array_unique($def);
  4592. if (count($select_array) < count($def)) {
  4593. $temp_module_strings = return_module_language($current_language, $module);
  4594. $temp_duplicate_array = array_diff_assoc($def, $select_array);
  4595. $temp_duplicate_array = array_merge($temp_duplicate_array, array_intersect($select_array, $temp_duplicate_array));
  4596. foreach ($temp_duplicate_array as $temp_key => $temp_value) {
  4597. // Don't add duplicate relationships
  4598. if (!empty($var_def[$temp_key]['relationship']) && array_key_exists($var_def[$temp_key]['relationship'], $select_array)) {
  4599. continue;
  4600. }
  4601. $select_array[$temp_key] = $temp_value;
  4602. }
  4603. // Add the relationship name for easier recognition
  4604. foreach ($select_array as $key => $value) {
  4605. $select_array[$key] .= ' ('.$key.')';
  4606. }
  4607. }
  4608. asort($select_array);
  4609. return $select_array;
  4610. }
  4611. /**
  4612. * Gets the list of "*type_display*".
  4613. *
  4614. * @return array
  4615. */
  4616. function getTypeDisplayList()
  4617. {
  4618. return array('record_type_display', 'parent_type_display', 'record_type_display_notes');
  4619. }
  4620. /**
  4621. * Breaks given string into substring according
  4622. * to 'db_concat_fields' from field definition
  4623. * and assigns values to corresponding properties
  4624. * of bean.
  4625. *
  4626. * @param SugarBean $bean
  4627. * @param array $fieldDef
  4628. * @param string $value
  4629. */
  4630. function assignConcatenatedValue(SugarBean $bean, $fieldDef, $value)
  4631. {
  4632. $valueParts = explode(' ', $value);
  4633. $valueParts = array_filter($valueParts);
  4634. $fieldNum = count($fieldDef['db_concat_fields']);
  4635. if (count($valueParts) == 1 && $fieldDef['db_concat_fields'] == array('first_name', 'last_name')) {
  4636. $bean->last_name = $value;
  4637. } // elseif ($fieldNum >= count($valueParts))
  4638. else {
  4639. for ($i = 0; $i < $fieldNum; ++$i) {
  4640. $fieldValue = array_shift($valueParts);
  4641. $fieldName = $fieldDef['db_concat_fields'][$i];
  4642. $bean->$fieldName = $fieldValue !== false ? $fieldValue : '';
  4643. }
  4644. if (!empty($valueParts)) {
  4645. $bean->$fieldName .= ' '.implode(' ', $valueParts);
  4646. }
  4647. }
  4648. }
  4649. /**
  4650. * Performs unserialization. Accepts all types except Objects.
  4651. *
  4652. * @param string $value Serialized value of any type except Object
  4653. *
  4654. * @return mixed False if Object, converted value for other cases
  4655. */
  4656. function sugar_unserialize($value)
  4657. {
  4658. preg_match('/[oc]:\d+:/i', $value, $matches);
  4659. if (count($matches)) {
  4660. return false;
  4661. }
  4662. return unserialize($value);
  4663. }
  4664. define('DEFAULT_UTIL_SUITE_ENCODING', 'UTF-8');
  4665. function suite_strlen($input, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
  4666. {
  4667. if (function_exists('mb_strlen')) {
  4668. return mb_strlen($input, $encoding);
  4669. } else {
  4670. return strlen($input);
  4671. }
  4672. }
  4673. function suite_substr($input, $start, $length = null, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
  4674. {
  4675. if (function_exists('mb_substr')) {
  4676. return mb_substr($input, $start, $length, $encoding);
  4677. } else {
  4678. return substr($input, $start, $length);
  4679. }
  4680. }
  4681. function suite_strtoupper($input, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
  4682. {
  4683. if (function_exists('mb_strtoupper')) {
  4684. return mb_strtoupper($input, $encoding);
  4685. } else {
  4686. return strtoupper($input);
  4687. }
  4688. }
  4689. function suite_strtolower($input, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
  4690. {
  4691. if (function_exists('mb_strtolower')) {
  4692. return mb_strtolower($input, $encoding);
  4693. } else {
  4694. return strtolower($input);
  4695. }
  4696. }
  4697. function suite_strpos($haystack, $needle, $offset = 0, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
  4698. {
  4699. if (function_exists('mb_strpos')) {
  4700. return mb_strpos($haystack, $needle, $offset, $encoding);
  4701. } else {
  4702. return strpos($haystack, $needle, $offset);
  4703. }
  4704. }
  4705. function suite_strrpos($haystack, $needle, $offset = 0, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
  4706. {
  4707. if (function_exists('mb_strrpos')) {
  4708. return mb_strrpos($haystack, $needle, $offset, $encoding);
  4709. } else {
  4710. return strrpos($haystack, $needle, $offset);
  4711. }
  4712. }