Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

modules/EmailTemplates/EmailTemplate.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2 1
if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
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 [email protected].
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
/*********************************************************************************
42
 * Description:  TODO: To be written.
43
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
44
 * All Rights Reserved.
45
 * Contributor(s): ______________________________________..
46
 ********************************************************************************/
47
// EmailTemplate is used to store email email_template information.
48
class EmailTemplate extends SugarBean
49
{
50
    var $field_name_map = array();
51
    // Stored fields
52
    var $id;
53
    var $date_entered;
54
    var $date_modified;
55
    var $modified_user_id;
56
    var $created_by;
57
    var $created_by_name;
58
    var $modified_by_name;
59
    var $assigned_user_id;
60
    var $assigned_user_name;
61
    var $name;
62
    var $published;
63
    var $description;
64
    var $body;
65
    var $body_html;
66
    var $subject;
67
    var $attachments;
68
    var $from_name;
69
    var $from_address;
70
    var $table_name = "email_templates";
71
    var $object_name = "EmailTemplate";
72
    var $module_dir = "EmailTemplates";
73
    var $new_schema = true;
74
    // This is used to retrieve related fields from form posts.
75
    var $additional_column_fields = array();
76
    // add fields here that would not make sense in an email template
77
    var $badFields = array(
78
        'account_description',
79
        'contact_id',
80
        'lead_id',
81
        'opportunity_amount',
82
        'opportunity_id',
83
        'opportunity_name',
84
        'opportunity_role_id',
85
        'opportunity_role_fields',
86
        'opportunity_role',
87
        'campaign_id',
88
        // User objects
89
        'id',
90
        'date_entered',
91
        'date_modified',
92
        'user_preferences',
93
        'accept_status',
94
        'user_hash',
95
        'authenticate_id',
96
        'sugar_login',
97
        'reports_to_id',
98
        'reports_to_name',
99
        'is_admin',
100
        'receive_notifications',
101
        'modified_user_id',
102
        'modified_by_name',
103
        'created_by',
104
        'created_by_name',
105
        'accept_status_id',
106
        'accept_status_name',
107
    );
108
109
    /**
110
     * @var array temp storage for template variables while cleanBean
111
     */
112
    protected $storedVariables = array();
113
114 26
    public function __construct()
115
    {
116 26
        parent::__construct();
117 26
    }
118
119
    /**
120
     * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead
121
     */
122
    public function EmailTemplate(){
123
        $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
124
        if(isset($GLOBALS['log'])) {
125
            $GLOBALS['log']->deprecated($deprecatedMessage);
126
        }
127
        else {
128
            trigger_error($deprecatedMessage, E_USER_DEPRECATED);
129
        }
130
        self::__construct();
131
    }
132
133
134
    /**
135
     * Generates the extended field_defs for creating macros
136
     * @return array
137
     */
138 1
    function generateFieldDefsJS()
139
    {
140 1
        global $current_user;
141
142
143 1
        $contact = new Contact();
144 1
        $account = new Account();
145 1
        $lead = new Lead();
146 1
        $prospect = new Prospect();
147
148
149
        $loopControl = array(
150
            'Contacts' => array(
151 1
                'Contacts' => $contact,
152 1
                'Leads' => $lead,
153 1
                'Prospects' => $prospect,
154
            ),
155
            'Accounts' => array(
156 1
                'Accounts' => $account,
157
            ),
158
            'Users' => array(
159 1
                'Users' => $current_user,
160
            ),
161
        );
162
163
        $prefixes = array(
164 1
            'Contacts' => 'contact_',
165
            'Accounts' => 'account_',
166
            'Users' => 'contact_user_',
167
        );
168
169 1
        $collection = array();
170 1
        foreach ($loopControl as $collectionKey => $beans) {
171 1
            $collection[$collectionKey] = array();
172 1
            foreach ($beans as $beankey => $bean) {
173
174 1
                foreach ($bean->field_defs as $key => $field_def) {
175 1
                    if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) ||
176 1
                        ($field_def['type'] == 'assigned_user_name' || $field_def['type'] == 'link') ||
177 1
                        ($field_def['type'] == 'bool') ||
178 1
                        (in_array($field_def['name'], $this->badFields))
179
                    ) {
180 1
                        continue;
181
                    }
182 1
                    if (!isset($field_def['vname'])) {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
183
                        //echo $key;
184
                    }
185
                    // valid def found, process
186 1
                    $optionKey = strtolower("{$prefixes[$collectionKey]}{$key}");
187 1
                    $optionLabel = preg_replace('/:$/', "", translate($field_def['vname'], $beankey));
188 1
                    $dup = 1;
189 1
                    foreach ($collection[$collectionKey] as $value) {
190 1
                        if ($value['name'] == $optionKey) {
191 1
                            $dup = 0;
192 1
                            break;
193
                        }
194
                    }
195 1
                    if ($dup)
196 1
                        $collection[$collectionKey][] = array("name" => $optionKey, "value" => $optionLabel);
197
                }
198
            }
199
        }
200
201 1
        $json = getJSONobj();
202 1
        $ret = "var field_defs = ";
203 1
        $ret .= $json->encode($collection, false);
204 1
        $ret .= ";";
205 1
        return $ret;
206
    }
207
208
    function generateFieldDefsJS2()
209
    {
210
        global $current_user;
211
212
        $contact = new Contact();
213
        $account = new Account();
214
        $lead = new Lead();
215
        $prospect = new Prospect();
216
        $event = new FP_events();
217
218
219
        $loopControl = array(
220
            'Contacts' => array(
221
                'Contacts' => $contact,
222
                'Leads' => $lead,
223
                'Prospects' => $prospect,
224
            ),
225
            'Accounts' => array(
226
                'Accounts' => $account,
227
            ),
228
            'Users' => array(
229
                'Users' => $current_user,
230
            ),
231
            'Events' => array(
232
                'Events' => $event,
233
            ),
234
        );
235
236
        $prefixes = array(
237
            'Contacts' => 'contact_',
238
            'Accounts' => 'account_',
239
            'Users' => 'contact_user_',
240
            'Events' => 'event_',
241
        );
242
243
        $collection = array();
244
        foreach ($loopControl as $collectionKey => $beans) {
245
            $collection[$collectionKey] = array();
246
            foreach ($beans as $beankey => $bean) {
247
248
                foreach ($bean->field_defs as $key => $field_def) {
249
                    if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) ||
250
                        ($field_def['type'] == 'assigned_user_name' || $field_def['type'] == 'link') ||
251
                        ($field_def['type'] == 'bool') ||
252
                        (in_array($field_def['name'], $this->badFields))
253
                    ) {
254
                        continue;
255
                    }
256
                    if (!isset($field_def['vname'])) {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
257
                        //echo $key;
258
                    }
259
                    // valid def found, process
260
                    $optionKey = strtolower("{$prefixes[$collectionKey]}{$key}");
261
                    $optionLabel = preg_replace('/:$/', "", translate($field_def['vname'], $beankey));
262
                    $dup = 1;
263
                    foreach ($collection[$collectionKey] as $value) {
264
                        if ($value['name'] == $optionKey) {
265
                            $dup = 0;
266
                            break;
267
                        }
268
                    }
269
                    if ($dup)
270
                        $collection[$collectionKey][] = array("name" => $optionKey, "value" => $optionLabel);
271
                }
272
            }
273
        }
274
275
        $json = getJSONobj();
276
        $ret = "var field_defs = ";
277
        $ret .= $json->encode($collection, false);
278
        $ret .= ";";
279
        return $ret;
280
    }
281
282 1
    function get_summary_text()
283
    {
284 1
        return "$this->name";
285
    }
286
287 1
    function create_export_query($order_by, $where)
288
    {
289 1
        return $this->create_new_list_query($order_by, $where);
290
    }
291
292 1
    function fill_in_additional_list_fields()
293
    {
294 1
        $this->fill_in_additional_parent_fields();
295 1
    }
296
297 1
    function fill_in_additional_detail_fields()
298
    {
299 1
        if (empty($this->body) && !empty($this->body_html)) {
300 1
            global $sugar_config;
301 1
            $this->body = strip_tags(html_entity_decode($this->body_html, ENT_COMPAT, $sugar_config['default_charset']));
0 ignored issues
show
The call to html_entity_decode() has too many arguments starting with $sugar_config['default_charset'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
302
        }
303 1
        $this->created_by_name = get_assigned_user_name($this->created_by);
304 1
        $this->modified_by_name = get_assigned_user_name($this->modified_user_id);
305 1
        $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id);
306 1
        $this->fill_in_additional_parent_fields();
307 1
    }
308
309 3
    function fill_in_additional_parent_fields()
310
    {
311 3
    }
312
313 1
    function get_list_view_data()
314
    {
315 1
        global $app_list_strings, $focus, $action, $currentModule;
316 1
        $fields = $this->get_list_view_array();
317
        //$fields["DATE_MODIFIED"] = substr($fields["DATE_MODIFIED"], 0, 10);
318 1
        $fields["DATE_MODIFIED"] = isset($fields["DATE_MODIFIED"]) && !empty($fields["DATE_MODIFIED"]) ? substr($fields["DATE_MODIFIED"], 0, 10) : false;
319 1
        return $fields;
320
    }
321
322
//function all string that match the pattern {.} , also catches the list of found strings.
323
    //the cache will get refreshed when the template bean instance changes.
324
    //The found url key patterns are replaced with name value pairs provided as function parameter. $tracked_urls.
325
    //$url_template is used to construct the url for the email message. the template should have place holder for 1 variable parameter, represented by %1
326
    //$template_text_array is a list of text strings that need to be searched. usually the subject, html body and text body of the email message.
327
    //$removeme_url_template, if the url has is_optout property checked then use this template.
328 1
    function parse_tracker_urls($template_text_array, $url_template, $tracked_urls, $removeme_url_template)
329
    {
330 1
        global $beanFiles, $beanList, $app_list_strings, $sugar_config;
331 1
        if (!isset($this->parsed_urls))
332 1
            $this->parsed_urls = array();
333
334 1
        $return_array = $template_text_array;
335 1
        if (count($tracked_urls) > 0) {
336
            //parse the template and find all the dynamic strings that need replacement.
337
            foreach ($template_text_array as $key => $template_text) {
338
                if (!empty($template_text)) {
339
340
                    if (!isset($this->parsed_urls[$key]) || $this->parsed_urls[$key]['text'] != $template_text) {
341
                        // Fix for bug52014.
342
                        $template_text = urldecode($template_text);
343
                        $matches = $this->_preg_match_tracker_url($template_text);
344
                        $count = count($matches[0]);
345
                        $this->parsed_urls[$key] = array('matches' => $matches, 'text' => $template_text);
346
                    } else {
347
                        $matches = $this->parsed_urls[$key]['matches'];
348
                        if (!empty($matches[0])) {
349
                            $count = count($matches[0]);
350
                        } else {
351
                            $count = 0;
352
                        }
353
                    }
354
355
                    //navigate thru all the matched keys and replace the keys with actual strings.
356
357
                    if ($count > 0) {
358
                        for ($i = ($count - 1); $i >= 0; $i--) {
359
                            $url_key_name = $matches[0][$i][0];
360
                            if (!empty($tracked_urls[$url_key_name])) {
361
                                if ($tracked_urls[$url_key_name]['is_optout'] == 1) {
362
                                    $tracker_url = $removeme_url_template;
363
                                } else {
364
                                    $tracker_url = sprintf($url_template, $tracked_urls[$url_key_name]['id']);
365
                                }
366
                            }
367
                            if (!empty($tracker_url) && !empty($template_text) && !empty($matches[0][$i][0]) && !empty($tracked_urls[$matches[0][$i][0]])) {
368
                                $template_text = substr_replace($template_text, $tracker_url, $matches[0][$i][1], strlen($matches[0][$i][0]));
369
                                $template_text = str_replace($sugar_config['site_url'] . '/' . $sugar_config['site_url'], $sugar_config['site_url'], $template_text);
370
                            }
371
                        }
372
                    }
373
                }
374
                $return_array[$key] = $template_text;
375
            }
376
        }
377 1
        return $return_array;
378
    }
379
380
    /**
381
     *
382
     * Method for replace "preg_match_all" in method "parse_tracker_urls"
383
     * @param $text string String in which we need to search all string that match the pattern {.}
384
     * @return array result of search
385
     */
386
    private function _preg_match_tracker_url($text)
387
    {
388
        $result = array();
389
        $ind = 0;
390
        $switch = false;
391
        for ($i = 0; $i < strlen($text); $i++) {
392
            if ($text[$i] == '{') {
393
                $ind = $i;
394
                $switch = true;
395
            } elseif ($text[$i] == '}' && $switch === true) {
396
                $switch = false;
397
                array_push($result, array(substr($text, $ind, $i - $ind + 1), $ind));
398
            }
399
        }
400
        return array($result);
401
    }
402
403 1
    function parse_email_template($template_text_array, $focus_name, $focus, &$macro_nv)
404
    {
405 1
        global $beanList, $app_list_strings;
406
407
        // generate User instance that owns this "Contact" for contact_user_* macros
408 1
        $user = new User();
409 1
        if (isset($focus->assigned_user_id) && !empty($focus->assigned_user_id)) {
410
            $user->retrieve($focus->assigned_user_id);
411
        }
412
413 1
        if (!isset($this->parsed_entities))
414 1
            $this->parsed_entities = array();
415
416
        //parse the template and find all the dynamic strings that need replacement.
417
        // Bug #48111 It's strange why prefix for User module is contact_user (see self::generateFieldDefsJS method)
418 1
        if ($beanList[$focus_name] == 'User') {
419
            $pattern_prefix = '$contact_user_';
420
        } else {
421 1
            $pattern_prefix = '$' . strtolower($beanList[$focus_name]) . '_';
422
        }
423 1
        $pattern_prefix_length = strlen($pattern_prefix);
424 1
        $pattern = '/\\' . $pattern_prefix . '[A-Za-z_0-9]*/';
425
426 1
        $return_array = array();
427 1
        foreach ($template_text_array as $key => $template_text) {
428 1
            if (!isset($this->parsed_entities[$key])) {
429 1
                $matches = array();
430 1
                $count = preg_match_all($pattern, $template_text, $matches, PREG_OFFSET_CAPTURE);
431
432 1
                if ($count != 0) {
433
                    for ($i = ($count - 1); $i >= 0; $i--) {
434
                        if (!isset($matches[0][$i][2])) {
435
                            //find the field name in the bean.
436
                            $matches[0][$i][2] = substr($matches[0][$i][0], $pattern_prefix_length, strlen($matches[0][$i][0]) - $pattern_prefix_length);
437
438
                            //store the localized strings if the field is of type enum..
439
                            if (isset($focus->field_defs[$matches[0][$i][2]]) && $focus->field_defs[$matches[0][$i][2]]['type'] == 'enum' && isset($focus->field_defs[$matches[0][$i][2]]['options'])) {
440
                                $matches[0][$i][3] = $focus->field_defs[$matches[0][$i][2]]['options'];
441
                            }
442
                        }
443
                    }
444
                }
445 1
                $this->parsed_entities[$key] = $matches;
446
            } else {
447
                $matches = $this->parsed_entities[$key];
448
                if (!empty($matches[0])) {
449
                    $count = count($matches[0]);
450
                } else {
451
                    $count = 0;
452
                }
453
            }
454
455 1
            for ($i = ($count - 1); $i >= 0; $i--) {
456
                $field_name = $matches[0][$i][2];
457
458
                // cn: feel for User object attribute key and assign as found
459
                if (strpos($field_name, "user_") === 0) {
460
                    $userFieldName = substr($field_name, 5);
461
                    $value = $user->$userFieldName;
462
                    //_pp($userFieldName."[{$value}]");
463
                } else {
464
                    $value = $focus->{$field_name};
465
                }
466
467
                //check dom
468
                if (isset($matches[0][$i][3])) {
469
                    if (isset($app_list_strings[$matches[0][$i][3]][$value])) {
470
                        $value = $app_list_strings[$matches[0][$i][3]][$value];
471
                    }
472
                }
473
474
                //generate name value pair array of macros and corresponding values for the targed.
475
                $macro_nv[$matches[0][$i][0]] = $value;
476
477
                $template_text = substr_replace($template_text, $value, $matches[0][$i][1], strlen($matches[0][$i][0]));
478
            }
479
480
            //parse the template for tracker url strings. patter for these strings in {[a-zA-Z_0-9]+}
481
482 1
            $return_array[$key] = $template_text;
483
        }
484
485 1
        return $return_array;
486
    }
487
488
    /**
489
     * Convenience method to convert raw value into appropriate type format
490
     * @param string $type
491
     * @param string $value
492
     * @return string
493
     */
494 3
    function _convertToType($type, $value)
495
    {
496
        switch ($type) {
497 3
            case 'currency' :
0 ignored issues
show
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
498 1
                return currency_format_number($value);
499
            default:
500 3
                return $value;
501
        }
502
    }
503
504
    /**
505
     * Convenience method to parse for user's values in a template
506
     * @param array $repl_arr
507
     * @param object $user
508
     * @return array
509
     */
510 2
    function _parseUserValues($repl_arr, &$user)
511
    {
512 2
        foreach ($user->field_defs as $field_def) {
513 2
            if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
514 2
                continue;
515
            }
516
517 2
            $fieldName = $field_def['name'];
518 2
            if ($field_def['type'] == 'enum') {
519 2
                $translated = translate($field_def['options'], 'Users', $user->$fieldName);
520
521 2
                if (isset($translated) && !is_array($translated)) {
522
                    $repl_arr["contact_user_" . $fieldName] = $translated;
523
                } else { // unset enum field, make sure we have a match string to replace with ""
524 2
                    $repl_arr["contact_user_" . $fieldName] = '';
525
                }
526
            } else {
527 2
                if (isset($user->$fieldName)) {
528
                    // bug 47647 - allow for fields to translate before adding to template
529 2
                    $repl_arr["contact_user_" . $fieldName] = self::_convertToType($field_def['type'], $user->$fieldName);
530
                } else {
531 2
                    $repl_arr["contact_user_" . $fieldName] = "";
532
                }
533
            }
534
        }
535
536 2
        return $repl_arr;
537
    }
538
539
540 2
    function parse_template_bean($string, $bean_name, &$focus)
541
    {
542 2
        global $current_user;
543 2
        global $beanList;
544 2
        $repl_arr = array();
545
546
        // cn: bug 9277 - create a replace array with empty strings to blank-out invalid vars
547 2
        $acct = new Account();
548 2
        $contact = new Contact();
549 2
        $lead = new Lead();
550 2
        $prospect = new Prospect();
551
552 2
        foreach ($lead->field_defs as $field_def) {
553 2
            if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
554 2
                continue;
555
            }
556 2
            $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
557 2
                'contact_' . $field_def['name'] => '',
558 2
                'contact_account_' . $field_def['name'] => '',
559
            ));
560
        }
561 2
        foreach ($prospect->field_defs as $field_def) {
562 2
            if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
563 2
                continue;
564
            }
565 2
            $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
566 2
                'contact_' . $field_def['name'] => '',
567 2
                'contact_account_' . $field_def['name'] => '',
568
            ));
569
        }
570 2
        foreach ($contact->field_defs as $field_def) {
571 2
            if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
572 2
                continue;
573
            }
574 2
            $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
575 2
                'contact_' . $field_def['name'] => '',
576 2
                'contact_account_' . $field_def['name'] => '',
577
            ));
578
        }
579 2
        foreach ($acct->field_defs as $field_def) {
580 2
            if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
581 2
                continue;
582
            }
583 2
            $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
584 2
                'account_' . $field_def['name'] => '',
585 2
                'account_contact_' . $field_def['name'] => '',
586
            ));
587
        }
588
        // cn: end bug 9277 fix
589
590
591
        // feel for Parent account, only for Contacts traditionally, but written for future expansion
592 2
        if (isset($focus->account_id) && !empty($focus->account_id)) {
593
            $acct->retrieve($focus->account_id);
594
        }
595
596 2
        if ($bean_name == 'Contacts') {
597
            // cn: bug 9277 - email templates not loading account/opp info for templates
598 2
            if (!empty($acct->id)) {
599
                foreach ($acct->field_defs as $field_def) {
600
                    if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
601
                        continue;
602
                    }
603
604
                    $fieldName = $field_def['name'];
605
                    if ($field_def['type'] == 'enum') {
606
                        $translated = translate($field_def['options'], 'Accounts', $acct->$fieldName);
607
608
                        if (isset($translated) && !is_array($translated)) {
609
                            $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
610
                                'account_' . $fieldName => $translated,
611
                                'contact_account_' . $fieldName => $translated,
612
                            ));
613
                        } else { // unset enum field, make sure we have a match string to replace with ""
614
                            $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
615
                                'account_' . $fieldName => '',
616
                                'contact_account_' . $fieldName => '',
617
                            ));
618
                        }
619
                    } else {
620
                        // bug 47647 - allow for fields to translate before adding to template
621
                        $translated = self::_convertToType($field_def['type'], $acct->$fieldName);
622
                        $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
623
                            'account_' . $fieldName => $translated,
624
                            'contact_account_' . $fieldName => $translated,
625
                        ));
626
                    }
627
                }
628
            }
629
630 2
            if (!empty($focus->assigned_user_id)) {
631
                $user = new User();
632
                $user->retrieve($focus->assigned_user_id);
633 2
                $repl_arr = EmailTemplate::_parseUserValues($repl_arr, $user);
634
            }
635 2
        } elseif ($bean_name == 'Users') {
636
            /**
637
             * This section of code will on do work when a blank Contact, Lead,
638
             * etc. is passed in to parse the contact_* vars.  At this point,
639
             * $current_user will be used to fill in the blanks.
640
             */
641 2
            $repl_arr = EmailTemplate::_parseUserValues($repl_arr, $current_user);
642
        } else {
643
            // assumed we have an Account in focus
644 1
            foreach ($contact->field_defs as $field_def) {
645 1
                if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name' || $field_def['type'] == 'link') {
646 1
                    continue;
647
                }
648
649 1
                $fieldName = $field_def['name'];
650 1
                if ($field_def['type'] == 'enum') {
651 1
                    $translated = translate($field_def['options'], 'Accounts', $contact->$fieldName);
652
653 1
                    if (isset($translated) && !is_array($translated)) {
654 1
                        $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
655 1
                            'contact_' . $fieldName => $translated,
656 1
                            'contact_account_' . $fieldName => $translated,
657
                        ));
658
                    } else { // unset enum field, make sure we have a match string to replace with ""
659 1
                        $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
660 1
                            'contact_' . $fieldName => '',
661 1
                            'contact_account_' . $fieldName => '',
662
                        ));
663
                    }
664
                } else {
665 1
                    if (isset($contact->$fieldName)) {
666
                        // bug 47647 - allow for fields to translate before adding to template
667 1
                        $translated = self::_convertToType($field_def['type'], $contact->$fieldName);
668 1
                        $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
669 1
                            'contact_' . $fieldName => $translated,
670 1
                            'contact_account_' . $fieldName => $translated,
671
                        ));
672
                    } // if
673
                }
674
            }
675
        }
676
677
        ///////////////////////////////////////////////////////////////////////
678
        ////	LOAD FOCUS DATA INTO REPL_ARR
679 2
        foreach ($focus->field_defs as $field_def) {
680 2
            $fieldName = $field_def['name'];
681 2
            if (isset($focus->$fieldName)) {
682 2
                if (($field_def['type'] == 'relate' && empty($field_def['custom_type'])) || $field_def['type'] == 'assigned_user_name') {
683 1
                    continue;
684
                }
685
686 2
                if ($field_def['type'] == 'enum' && isset($field_def['options'])) {
687 2
                    $translated = translate($field_def['options'], $bean_name, $focus->$fieldName);
688
689 2
                    if (isset($translated) && !is_array($translated)) {
690 2
                        $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
691 2
                            strtolower($beanList[$bean_name]) . "_" . $fieldName => $translated,
692
                        ));
693
                    } else { // unset enum field, make sure we have a match string to replace with ""
694 1
                        $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
695 2
                            strtolower($beanList[$bean_name]) . "_" . $fieldName => '',
696
                        ));
697
                    }
698
                } else {
699
                    // bug 47647 - translate currencies to appropriate values
700 2
                    $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
701 2
                        strtolower($beanList[$bean_name]) . "_" . $fieldName => self::_convertToType($field_def['type'], $focus->$fieldName),
702
                    ));
703
                }
704
            } else {
705 1
                if ($fieldName == 'full_name') {
706 1
                    $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
707 1
                        strtolower($beanList[$bean_name]) . '_full_name' => $focus->get_summary_text(),
708
                    ));
709
                } else {
710 1
                    $repl_arr = EmailTemplate::add_replacement($repl_arr, $field_def, array(
711 2
                        strtolower($beanList[$bean_name]) . "_" . $fieldName => '',
712
                    ));
713
                }
714
            }
715
        } // end foreach()
716
717 2
        krsort($repl_arr);
718 2
        reset($repl_arr);
719
        //20595 add nl2br() to respect the multi-lines formatting
720 2
        if (isset($repl_arr['contact_primary_address_street'])) {
721 2
            $repl_arr['contact_primary_address_street'] = nl2br($repl_arr['contact_primary_address_street']);
722
        }
723 2
        if (isset($repl_arr['contact_alt_address_street'])) {
724 2
            $repl_arr['contact_alt_address_street'] = nl2br($repl_arr['contact_alt_address_street']);
725
        }
726
727 2
        foreach ($repl_arr as $name => $value) {
728 2
            if ($value != '' && is_string($value)) {
729 2
                $string = str_replace("\$$name", $value, $string);
730
            } else {
731 2
                $string = str_replace("\$$name", ' ', $string);
732
            }
733
        }
734
735 2
        return $string;
736
    }
737
738
    /**
739
     * Add replacement(s) to the collection based on field definition
740
     *
741
     * @param array $data
742
     * @param array $field_def
743
     * @param array $replacement
744
     * @return array
745
     */
746 2
    protected static function add_replacement($data, $field_def, $replacement)
747
    {
748 2
        foreach ($replacement as $key => $value) {
749
            // @see defect #48641
750 2
            if ('multienum' == $field_def['type']) {
751
                $value = implode(', ', unencodeMultienum($value));
752
            }
753 2
            $data[$key] = $value;
754
        }
755 2
        return $data;
756
    }
757
758 1
    function parse_template($string, &$bean_arr)
759
    {
760 1
        foreach ($bean_arr as $bean_name => $bean_id) {
761
762 1
            $focus = BeanFactory::getBean($bean_name,$bean_id);
763
764 1
            if ($bean_name == 'Leads' || $bean_name == 'Prospects') {
765 1
                $bean_name = 'Contacts';
766
            }
767
768 1
            if (isset($this) && isset($this->module_dir) && $this->module_dir == 'EmailTemplates') {
769 1
                $string = $this->parse_template_bean($string, $bean_name, $focus);
770
            } else {
771 1
                $string = EmailTemplate::parse_template_bean($string, $bean_name, $focus);
772
            }
773
        }
774 1
        return $string;
775
    }
776
777 26
    function bean_implements($interface)
778
    {
779
        switch ($interface) {
780 26
            case 'ACL':
781 26
                return true;
782
        }
783 1
        return false;
784
    }
785
786 1
    static function getTypeOptionsForSearch()
787
    {
788 1
        $template = new EmailTemplate();
789 1
        $optionKey = $template->field_defs['type']['options'];
790 1
        $options = $GLOBALS['app_list_strings'][$optionKey];
791 1
        if (!is_admin($GLOBALS['current_user']) && isset($options['workflow']))
792
            unset($options['workflow']);
793
794 1
        return $options;
795
    }
796
797 1
    function is_used_by_email_marketing()
798
    {
799 1
        $query = "select id from email_marketing where template_id='$this->id' and deleted=0";
800 1
        $result = $this->db->query($query);
801 1
        if ($this->db->fetchByAssoc($result)) {
802
            return true;
803
        }
804 1
        return false;
805
    }
806
807
    /**
808
     * Allows us to save variables of template as they are
809
     */
810 1
    public function cleanBean()
811
    {
812 1
        $this->storedVariables = array();
813 1
        $this->body_html = preg_replace_callback('/\{::[^}]+::\}/', array($this, 'storeVariables'), $this->body_html);
814 1
        parent::cleanBean();
815 1
        $this->body_html = str_replace(array_values($this->storedVariables), array_keys($this->storedVariables), $this->body_html);
816 1
    }
817
818
    /**
819
     * Replacing variables of templates by their md5 hash
820
     *
821
     * @param array $text result of preg_replace_callback
822
     * @return string md5 hash of result
823
     */
824
    protected function storeVariables($text)
825
    {
826
        if (isset($this->storedVariables[$text[0]]) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
827
            $this->storedVariables[$text[0]] = md5($text[0]);
828
        }
829
        return $this->storedVariables[$text[0]];
830
    }
831
832
    public function save($check_notify = FALSE)
833
    {
834
        $this->repairMozaikClears();
835
       return parent::save($check_notify);
836
    }
837
838 2
    public function retrieve($id = -1, $encode = true, $deleted = true)
839
    {
840 2
        $ret = parent::retrieve($id, $encode, $deleted);
841 2
        $this->repairMozaikClears();
842 2
        return $ret;
843
    }
844
845 2
    private function repairMozaikClears() {
846
        // repair tinymce auto correction in mozaik clears
847 2
        $this->body_html = str_replace('&lt;div class=&quot;mozaik-clear&quot;&gt;&nbsp;&lt;br&gt;&lt;/div&gt;', '&lt;div class=&quot;mozaik-clear&quot;&gt;&lt;/div&gt;', $this->body_html);
848 2
    }
849
850
}
851
852
?>
853