Completed
Pull Request — master (#133)
by Goffy
16:45
created

XoopsMailer::setToUsers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 1
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 39 and the first side effect is on line 20.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * XOOPS mailer
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             kernel
15
 * @since               2.0.0
16
 * @author              Kazumi Ono (AKA onokazu) http://www.myweb.ne.jp/, http://jp.xoops.org/
17
 * @deprecated          use {@link XoopsMultiMailer} instead.
18
 */
19
20
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
21
22
xoops_loadLanguage('mail');
23
24
/**
25
 * The new Multimailer class that will carry out the actual sending and will later replace this class.
26
 * If you're writing new code, please use that class instead.
27
 */
28
include_once $GLOBALS['xoops']->path('class/mail/xoopsmultimailer.php');
29
30
/**
31
 * Class for sending mail.
32
 *
33
 * Changed to use the facilities of  {@link XoopsMultiMailer}
34
 *
35
 * @package    class
36
 * @subpackage mail
37
 * @author     Kazumi Ono <[email protected]>
38
 */
39
class XoopsMailer
40
{
41
    /**
42
     * reference to a {@link XoopsMultiMailer}
43
     *
44
     * @var XoopsMultiMailer
45
     * @access private
46
     * @since  21.02.2003 14:14:13
47
     */
48
    public $multimailer;
49
    // sender email address
50
    // private
51
    public $fromEmail;
52
    // sender name
53
    // private
54
    public $fromName;
55
    // RMV-NOTIFY
56
    // sender UID
57
    // private
58
    public $fromUser;
59
    // array of user class objects
60
    // private
61
    public $toUsers;
62
    // array of email addresses
63
    // private
64
    public $toEmails;
65
    // custom headers
66
    // private
67
    public $headers;
68
    // subject of mail
69
    // private
70
    public $subject;
71
    // body of mail
72
    // private
73
    public $body;
74
    // error messages
75
    // private
76
    public $errors;
77
    // messages upon success
78
    // private
79
    public $success;
80
    // private
81
    public $isMail;
82
    // private
83
    public $isPM;
84
    // private
85
    public $assignedTags;
86
    // private
87
    public $template;
88
    // private
89
    public $templatedir;
90
    // protected
91
    public $charSet = 'iso-8859-1';
92
    // protected
93
    public $encoding = '8bit';
94
95
    /**
96
     * Constructor
97
     *
98
     * @return XoopsMailer
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
99
     */
100
    public function __construct()
101
    {
102
        $this->multimailer = new XoopsMultiMailer();
103
        $this->reset();
104
    }
105
106
    /**
107
     * PHP 4 style constructor compatibility shim
108
     *
109
     * @deprecated all callers should be using parent::__construct()
110
     */
111
    public function XoopsMailer()
112
    {
113
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
114
        trigger_error("Should call parent::__construct in {$trace[0]['file']} line {$trace[0]['line']},");
115
        self::__construct();
116
    }
117
118
    /**
119
     * @param bool $value
120
     */
121
    public function setHTML($value = true)
122
    {
123
        $this->multimailer->isHTML($value);
124
    }
125
126
    // public
127
    // reset all properties to default
128
    public function reset()
129
    {
130
        $this->fromEmail    = '';
131
        $this->fromName     = '';
132
        $this->fromUser     = null; // RMV-NOTIFY
133
        $this->priority     = '';
0 ignored issues
show
Bug introduced by
The property priority does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
134
        $this->toUsers      = array();
135
        $this->toEmails     = array();
136
        $this->headers      = array();
137
        $this->subject      = '';
138
        $this->body         = '';
139
        $this->errors       = array();
140
        $this->success      = array();
141
        $this->isMail       = false;
142
        $this->isPM         = false;
143
        $this->assignedTags = array();
144
        $this->template     = '';
145
        $this->templatedir  = '';
146
        // Change below to \r\n if you have problem sending mail
147
        $this->LE = "\n";
0 ignored issues
show
Bug introduced by
The property LE does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
148
    }
149
150
    // public
151
    /**
152
     * @param null $value
153
     */
154
    public function setTemplateDir($value = null)
155
    {
156
        if ($value === null && is_object($GLOBALS['xoopsModule'])) {
157
            $value = $GLOBALS['xoopsModule']->getVar('dirname', 'n');
158
        } else {
159
            $value = str_replace(DIRECTORY_SEPARATOR, '/', $value);
160
        }
161
        $this->templatedir = $value;
162
    }
163
164
    // private
165
    /**
166
     * @return bool|string
167
     */
168
    public function getTemplatePath()
169
    {
170
        if (!$path = $this->templatedir) {
171
            $path = XOOPS_ROOT_PATH . '/language/';
172
        } elseif (false === strpos($path, '/')) {
173
            $path = XOOPS_ROOT_PATH . '/modules/' . $path . '/language/';
174
        } elseif (substr($path, -1, 1) !== '/') {
175
            $path .= '/';
176
        }
177
        if (file_exists($path . $GLOBALS['xoopsConfig']['language'] . '/mail_template/' . $this->template)) {
178
            return $path . $GLOBALS['xoopsConfig']['language'] . '/mail_template/' . $this->template;
179
        } elseif (file_exists($path . 'english/mail_template/' . $this->template)) {
180
            return $path . 'english/mail_template/' . $this->template;
181
        } elseif (file_exists($path . $this->template)) {
182
            return $path . $this->template;
183
        } else {
184
            return false;
185
        }
186
    }
187
188
    // public
189
    /**
190
     * @param $value
191
     */
192
    public function setTemplate($value)
193
    {
194
        $this->template = $value;
195
    }
196
197
    // pupblic
198
    /**
199
     * @param $value
200
     */
201
    public function setFromEmail($value)
202
    {
203
        $this->fromEmail = trim($value);
204
    }
205
206
    // public
207
    /**
208
     * @param $value
209
     */
210
    public function setFromName($value)
211
    {
212
        $this->fromName = trim($value);
213
    }
214
215
    // RMV-NOTIFY
216
    // public
217
    /**
218
     * @param $user
219
     */
220
    public function setFromUser($user)
221
    {
222
        if (strtolower(get_class($user)) === 'xoopsuser') {
223
            $this->fromUser = &$user;
224
        }
225
    }
226
227
    // public
228
    /**
229
     * @param $value
230
     */
231
    public function setPriority($value)
232
    {
233
        $this->priority = trim($value);
234
    }
235
236
    // public
237
    /**
238
     * @param $value
239
     */
240
    public function setSubject($value)
241
    {
242
        $this->subject = trim($value);
243
    }
244
245
    // public
246
    /**
247
     * @param $value
248
     */
249
    public function setBody($value)
250
    {
251
        $this->body = trim($value);
252
    }
253
254
    // public
255
    public function useMail()
256
    {
257
        $this->isMail = true;
258
    }
259
260
    // public
261
    public function usePM()
262
    {
263
        $this->isPM = true;
264
    }
265
266
    // public
267
    /**
268
     * @param bool $debug
269
     *
270
     * @return bool
271
     */
272
    public function send($debug = false)
273
    {
274
        global $xoopsConfig;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
275
        if ($this->body == '' && $this->template == '') {
276
            if ($debug) {
277
                $this->errors[] = _MAIL_MSGBODY;
278
            }
279
280
            return false;
281
        } elseif ($this->template != '') {
282
            $path = $this->getTemplatePath();
283
            if (!($fd = @fopen($path, 'r'))) {
284
                if ($debug) {
285
                    $this->errors[] = _MAIL_FAILOPTPL;
286
                }
287
288
                return false;
289
            }
290
            $this->setBody(fread($fd, filesize($path)));
291
        }
292
        // for sending mail only
293
        if ($this->isMail || !empty($this->toEmails)) {
294
            if (!empty($this->priority)) {
295
                $this->headers[] = 'X-Priority: ' . $this->priority;
296
            }
297
            // $this->headers[] = "X-Mailer: PHP/".phpversion();
298
            // $this->headers[] = "Return-Path: ".$this->fromEmail;
299
            $headers = implode($this->LE, $this->headers);
300
        }
301
        // TODO: we should have an option of no-reply for private messages and emails
302
        // to which we do not accept replies.  e.g. the site admin doesn't want a
303
        // a lot of message from people trying to unsubscribe.  Just make sure to
304
        // give good instructions in the message.
305
        // add some standard tags (user-dependent tags are included later)
306
        global $xoopsConfig;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
307
308
        $this->assign('X_ADMINMAIL', $xoopsConfig['adminmail']);
309
        $this->assign('X_SITENAME', $xoopsConfig['sitename']);
310
        $this->assign('X_SITEURL', XOOPS_URL . '/');
311
        // TODO: also X_ADMINNAME??
312
        // TODO: X_SIGNATURE, X_DISCLAIMER ?? - these are probably best
313
        // done as includes if mail templates ever get this sophisticated
314
        // replace tags with actual values
315
        foreach ($this->assignedTags as $k => $v) {
316
            $this->body    = str_replace('{' . $k . '}', $v, $this->body);
317
            $this->subject = str_replace('{' . $k . '}', $v, $this->subject);
318
        }
319
        $this->body = str_replace("\r\n", "\n", $this->body);
320
        $this->body = str_replace("\r", "\n", $this->body);
321
        $this->body = str_replace("\n", $this->LE, $this->body);
322
        // send mail to specified mail addresses, if any
323
        foreach ($this->toEmails as $mailaddr) {
324
            if (!$this->sendMail($mailaddr, $this->subject, $this->body, $headers)) {
0 ignored issues
show
Bug introduced by
The variable $headers does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
325
                if ($debug) {
326
                    $this->errors[] = sprintf(_MAIL_SENDMAILNG, $mailaddr);
327
                }
328
            } else {
329
                if ($debug) {
330
                    $this->success[] = sprintf(_MAIL_MAILGOOD, $mailaddr);
331
                }
332
            }
333
        }
334
        // send message to specified users, if any
335
        // NOTE: we don't send to LIST of recipients, because the tags
336
        // below are dependent on the user identity; i.e. each user
337
        // receives (potentially) a different message
338
        foreach ($this->toUsers as $user) {
339
            // set some user specific variables
340
            $subject = str_replace('{X_UNAME}', $user->getVar('uname'), $this->subject);
341
            $text    = str_replace('{X_UID}', $user->getVar('uid'), $this->body);
342
            $text    = str_replace('{X_UEMAIL}', $user->getVar('email'), $text);
343
            $text    = str_replace('{X_UNAME}', $user->getVar('uname'), $text);
344
            $text    = str_replace('{X_UACTLINK}', XOOPS_URL . '/register.php?op=actv&id=' . $user->getVar('uid') . '&actkey=' . $user->getVar('actkey'), $text);
345
            // send mail
346 View Code Duplication
            if ($this->isMail) {
347
                if (!$this->sendMail($user->getVar('email'), $subject, $text, $headers)) {
348
                    if ($debug) {
349
                        $this->errors[] = sprintf(_MAIL_SENDMAILNG, $user->getVar('uname'));
350
                    }
351
                } else {
352
                    if ($debug) {
353
                        $this->success[] = sprintf(_MAIL_MAILGOOD, $user->getVar('uname'));
354
                    }
355
                }
356
            }
357
            // send private message
358 View Code Duplication
            if ($this->isPM) {
359
                if (!$this->sendPM($user->getVar('uid'), $subject, $text)) {
360
                    if ($debug) {
361
                        $this->errors[] = sprintf(_MAIL_SENDPMNG, $user->getVar('uname'));
362
                    }
363
                } else {
364
                    if ($debug) {
365
                        $this->success[] = sprintf(_MAIL_PMGOOD, $user->getVar('uname'));
366
                    }
367
                }
368
            }
369
            flush();
370
        }
371
        return !(count($this->errors) > 0);
372
    }
373
374
    // private
375
    /**
376
     * @param $uid
377
     * @param $subject
378
     * @param $body
379
     *
380
     * @return bool
381
     */
382
    public function sendPM($uid, $subject, $body)
383
    {
384
        global $xoopsUser;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
385
        $pm_handler = xoops_getHandler('privmessage');
386
        $pm         = $pm_handler->create();
387
        $pm->setVar('subject', $subject);
388
        // RMV-NOTIFY
389
        $pm->setVar('from_userid', !empty($this->fromUser) ? $this->fromUser->getVar('uid') : (empty($xoopsUser) ? 1 : $xoopsUser->getVar('uid')));
390
        $pm->setVar('msg_text', $body);
391
        $pm->setVar('to_userid', $uid);
392
        if (!$pm_handler->insert($pm)) {
393
            return false;
394
        }
395
396
        return true;
397
    }
398
399
    /**
400
     * Send email
401
     *
402
     * Uses the new XoopsMultiMailer
403
     *
404
     * @param $email
405
     * @param $subject
406
     * @param $body
407
     * @param $headers
408
     *
409
     * @return bool
410
     */
411
    public function sendMail($email, $subject, $body, $headers)
0 ignored issues
show
Unused Code introduced by
The parameter $headers is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
412
    {
413
        $subject = $this->encodeSubject($subject);
414
        $this->encodeBody($body);
415
        $this->multimailer->clearAllRecipients();
416
        $this->multimailer->addAddress($email);
417
        $this->multimailer->Subject  = $subject;
418
        $this->multimailer->Body     = $body;
419
        $this->multimailer->CharSet  = $this->charSet;
420
        $this->multimailer->Encoding = $this->encoding;
421
        if (!empty($this->fromName)) {
422
            $this->multimailer->FromName = $this->encodeFromName($this->fromName);
423
        }
424
        if (!empty($this->fromEmail)) {
425
            $this->multimailer->Sender = $this->multimailer->From = $this->fromEmail;
426
        }
427
428
        $this->multimailer->clearCustomHeaders();
429
        foreach ($this->headers as $header) {
430
            $this->multimailer->addCustomHeader($header);
431
        }
432
        if (!$this->multimailer->send()) {
433
            $this->errors[] = $this->multimailer->ErrorInfo;
434
435
            return false;
436
        }
437
438
        return true;
439
    }
440
441
    // public
442
    /**
443
     * @param bool $ashtml
444
     *
445
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
446
     */
447
    public function getErrors($ashtml = true)
448
    {
449
        if (!$ashtml) {
450
            return $this->errors;
451
        } else {
452
            if (!empty($this->errors)) {
453
                $ret = '<h4>' . _ERRORS . '</h4>';
454
                foreach ($this->errors as $error) {
455
                    $ret .= $error . '<br>';
456
                }
457
            } else {
458
                $ret = '';
459
            }
460
461
            return $ret;
462
        }
463
    }
464
465
    // public
466
    /**
467
     * @param bool $ashtml
468
     *
469
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
470
     */
471
    public function getSuccess($ashtml = true)
472
    {
473
        if (!$ashtml) {
474
            return $this->success;
475
        } else {
476
            $ret = '';
477
            if (!empty($this->success)) {
478
                foreach ($this->success as $suc) {
479
                    $ret .= $suc . '<br>';
480
                }
481
            }
482
483
            return $ret;
484
        }
485
    }
486
487
    // public
488
    /**
489
     * @param      $tag
490
     * @param null $value
491
     */
492
    public function assign($tag, $value = null)
493
    {
494
        if (is_array($tag)) {
495
            foreach ($tag as $k => $v) {
496
                $this->assign($k, $v);
497
            }
498
        } else {
499
            if (!empty($tag) && isset($value)) {
500
                $tag = strtoupper(trim($tag));
501
                // RMV-NOTIFY
502
                // TEMPORARY FIXME: until the X_tags are all in here
503
                // if ( substr($tag, 0, 2) != "X_" ) {
504
                $this->assignedTags[$tag] = $value;
505
                // }
506
            }
507
        }
508
    }
509
510
    // public
511
    /**
512
     * @param $value
513
     */
514
    public function addHeaders($value)
515
    {
516
        $this->headers[] = trim($value) . $this->LE;
517
    }
518
519
    // public
520
    /**
521
     * @param $email
522
     */
523
    public function setToEmails($email)
524
    {
525
        if (!is_array($email)) {
526
            if (preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+([\.][a-z0-9-]+)+$/i", $email)) {
527
                array_push($this->toEmails, $email);
528
            }
529
        } else {
530
            foreach ($email as $e) {
531
                $this->setToEmails($e);
532
            }
533
        }
534
    }
535
536
    // public
537
    /**
538
     * @param $user
539
     */
540
    public function setToUsers(&$user)
541
    {
542
        if (!is_array($user)) {
543
            if (strtolower(get_class($user)) === 'xoopsuser') {
544
                array_push($this->toUsers, $user);
545
            }
546
        } else {
547
            foreach ($user as $u) {
548
                $this->setToUsers($u);
549
            }
550
        }
551
    }
552
553
    // public
554
    /**
555
     * @param $group
556
     */
557
    public function setToGroups($group)
558
    {
559
        if (!is_array($group)) {
560
            if (strtolower(get_class($group)) === 'xoopsgroup') {
561
                $member_handler = xoops_getHandler('member');
562
                $this->setToUsers($member_handler->getUsersByGroup($group->getVar('groupid'), true));
0 ignored issues
show
Bug introduced by
$member_handler->getUser...etVar('groupid'), true) cannot be passed to settousers() as the parameter $user expects a reference.
Loading history...
563
            }
564
        } else {
565
            foreach ($group as $g) {
566
                $this->setToGroups($g);
567
            }
568
        }
569
    }
570
571
    // abstract
572
    // to be overridden by lang specific mail class, if needed
573
    /**
574
     * @param $text
575
     *
576
     * @return mixed
577
     */
578
    public function encodeFromName($text)
579
    {
580
        return $text;
581
    }
582
583
    // abstract
584
    // to be overridden by lang specific mail class, if needed
585
    /**
586
     * @param $text
587
     *
588
     * @return mixed
589
     */
590
    public function encodeSubject($text)
591
    {
592
        return $text;
593
    }
594
595
    // abstract
596
    // to be overridden by lang specific mail class, if needed
597
    /**
598
     * @param $text
599
     */
600
    public function encodeBody(&$text)
0 ignored issues
show
Unused Code introduced by
The parameter $text is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
601
    {
602
    }
603
}
604