Completed
Branch dev (623cfe)
by Greg
03:59
created

classes/DomainMOD/Email.php (6 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
/**
3
 * /classes/DomainMOD/Email.php
4
 *
5
 * This file is part of DomainMOD, an open source domain and internet asset manager.
6
 * Copyright (c) 2010-2017 Greg Chetcuti <[email protected]>
7
 *
8
 * Project: http://domainmod.org   Author: http://chetcuti.com
9
 *
10
 * DomainMOD is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
11
 * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
12
 * version.
13
 *
14
 * DomainMOD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
15
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along with DomainMOD. If not, see
18
 * http://www.gnu.org/licenses/.
19
 *
20
 */
21
//@formatter:off
22
namespace DomainMOD;
23
24
class Email
25
{
26
    public $log;
27
    public $system;
28
    public $time;
29
30
    public function __construct()
31
    {
32
        $this->log = new Log('class.email');
33
        $this->system = new System();
34
        $this->time = new Time();
35
    }
36
37
    public function sendExpirations($from_cron)
1 ignored issue
show
sendExpirations uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
38
    {
39
        $timestamp_basic = $this->time->timeBasic();
40
        $timestamp_long = $this->time->timeLong();
41
42
        list($full_url, $from_address, $number_of_days, $use_smtp) = $this->getSettings();
43
        $send_to = $this->getRecipients();
44
        $subject = "Upcoming Expirations - " . $timestamp_long;
45
        $headers = $this->getHeaders($from_address);
46
47
        list($result_domains, $result_ssl) = $this->checkExpiring($number_of_days, $from_cron);
48
        $message_html = '';
49
        $message_html .= $this->messageTopHtml($full_url, $subject, $number_of_days);
50
        $message_html .= $this->showDomainsHtml($result_domains, $full_url, $timestamp_basic);
51
        $message_html .= $this->showSslHtml($result_ssl, $full_url, $timestamp_basic);
52
        $message_html .= $this->messageBottomHtml($full_url);
53
54
        list($result_domains, $result_ssl) = $this->checkExpiring($number_of_days, $from_cron);
55
        $message_text = '';
1 ignored issue
show
$message_text is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
56
        $message_text = $subject . "\n\n";
57
        $message_text .= $this->messageTopText($number_of_days);
58
        $message_text .= $this->showDomainsText($result_domains, $timestamp_basic);
59
        $message_text .= $this->showSslText($result_ssl, $timestamp_basic);
60
        $message_text .= $this->messageBottomText($full_url);
61
62
        foreach ($send_to as $row_recipients) {
1 ignored issue
show
The expression $send_to of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
63
64
            $full_to = '"' . $row_recipients->first_name . ' ' . $row_recipients->last_name . '"' . ' <' . $row_recipients->email_address . '>';
65
66
            if ($use_smtp != '1') {
67
68
                mail($full_to, $subject, $message_html, $headers, '-f' . $from_address);
69
70
            } else {
71
72
                $smtp = new Smtp();
73
                $smtp->send($from_address, $row_recipients->email_address, $row_recipients->first_name . ' ' .
74
                    $row_recipients->last_name, $subject, $message_html, $message_text);
75
76
            }
77
            sleep(2);
78
79
            $_SESSION['s_message_success'] .= 'Expiration Email Sent<BR>';
80
        }
81
    }
82
83
    public function getSettings()
84
    {
85
        $url = '';
86
        $email = '';
87
        $days = '';
88
        $use_smtp = '';
89
90
        $result = $this->system->db()->query("
91
            SELECT full_url, email_address, expiration_days, use_smtp
92
            FROM settings")->fetch();
93
94
        if (!$result) {
95
96
            $log_message = 'Unable to retrieve email settings';
97
            $this->log->error($log_message);
98
99
        } else {
100
101
            $url = $result->full_url;
102
            $email = $result->email_address;
103
            $days = $result->expiration_days;
104
            $use_smtp = $result->use_smtp;
105
106
        }
107
        return array($url, $email, $days, $use_smtp);
108
    }
109
110
    public function checkExpiring($days, $from_cron)
1 ignored issue
show
checkExpiring uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
111
    {
112
        $date = $this->time->timeBasicPlusDays($days);
113
        $pdo = $this->system->db();
114
115
        $stmt = $pdo->prepare("
116
            SELECT id, expiry_date, domain
117
            FROM domains
118
            WHERE active NOT IN ('0', '10')
119
              AND expiry_date <= :date
120
            ORDER BY expiry_date, domain");
121
        $stmt->bindValue('date', $date, \PDO::PARAM_STR);
122
        $stmt->execute();
123
        $result = $stmt->fetchAll();
124
125
        if (!$result) {
126
127
            $domains_expiring = '0';
128
129
        } else {
130
131
            $domains_expiring = $result;
132
133
        }
134
135
        $stmt = $pdo->prepare("
136
            SELECT sslc.id, sslc.expiry_date, sslc.name, sslt.type
137
            FROM ssl_certs AS sslc, ssl_cert_types AS sslt
138
            WHERE sslc.type_id = sslt.id
139
              AND sslc.active NOT IN ('0')
140
              AND sslc.expiry_date <= :date
141
            ORDER BY sslc.expiry_date, sslc.name");
142
        $stmt->bindValue('date', $date, \PDO::PARAM_STR);
143
        $stmt->execute();
144
        $result = $stmt->fetchAll();
145
146
        if (!$result) {
147
148
            $ssl_expiring = '0';
149
150
        } else {
151
152
            $ssl_expiring = $result;
153
154
        }
155
156
        if ($domains_expiring != '0' || $ssl_expiring != '0') {
157
            return array($domains_expiring, $ssl_expiring);
158
        } else {
159
            $_SESSION['s_message_success'] .= 'No Upcoming Expirations<BR>';
160
            if ($from_cron == '1') exit;
1 ignored issue
show
Coding Style Compatibility introduced by
The method checkExpiring() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
161
            return false;
162
        }
163
    }
164
165
    public function getRecipients()
1 ignored issue
show
getRecipients uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
166
    {
167
        $result = $this->system->db()->query("
168
            SELECT u.email_address, u.first_name, u.last_name
169
            FROM users AS u, user_settings AS us
170
            WHERE u.id = us.user_id
171
              AND u.active = '1'
172
              AND us.expiration_emails = '1'")->fetchAll();
173
174
        if (!$result) {
175
176
            $_SESSION['s_message_danger'] .= 'No Users Are Subscribed<BR>';
177
            return false;
178
179
        } else {
180
181
            return $result;
182
183
        }
184
    }
185
186
    public function getHeaders($from_address)
187
    {
188
        $headers = '';
189
        $headers .= 'MIME-Version: 1.0' . "\r\n";
190
        $headers .= 'Content-type: text/html; charset=' . EMAIL_ENCODING_TYPE . "\r\n";
191
        $headers .= 'From: "' . SOFTWARE_TITLE . '" <' . $from_address . ">\r\n";
192
        $headers .= 'Return-Path: ' . $from_address . "\r\n";
193
        $headers .= 'Reply-to: ' . $from_address . "\r\n";
194
        $version = phpversion();
195
        $headers .= 'X-Mailer: PHP/' . $version . "\r\n";
196
        return $headers;
197
    }
198
199
    public function messageTopHtml($full_url, $subject, $number_of_days)
200
    {
201
        ob_start(); ?>
202
        <html>
203
        <head><title><?php echo $subject; ?></title></head>
204
        <body bgcolor="#FFFFFF">
205
        <table width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF">
206
        <tr>
207
        <td width="100%" bgcolor="#FFFFFF">
208
        <font color="#000000" size="2" face="Verdana, Arial, Helvetica, sans-serif">
209
        <a title="<?php echo SOFTWARE_TITLE; ?>" href="<?php echo $full_url; ?>/"><img border="0" alt="<?php
210
            echo SOFTWARE_TITLE; ?>" src="<?php echo $full_url; ?>/images/logo.png"></a><BR><BR>Below is a
211
        list of all the Domains & SSL Certificates in <?php echo SOFTWARE_TITLE; ?> that are expiring in the next
212
        <?php echo $number_of_days; ?> days.<BR> <BR>If you would like to change the frequency of this email
213
        notification please contact your <?php echo SOFTWARE_TITLE; ?> administrator.<BR><BR><?php
214
        return ob_get_clean();
215
    }
216
217
    public function messageTopText($number_of_days)
218
    {
219
        $message = "Below is a list of all the Domains & SSL Certificates in " . SOFTWARE_TITLE . " that are expiring in the next " . $number_of_days . " days.\n\nIf you would like to change the frequency of this email notification please contact your " . SOFTWARE_TITLE . " administrator.\n\n";
220
        return $message;
221
    }
222
223
    public function showDomainsHtml($result_domains, $full_url, $timestamp_basic)
224
    {
225
        ob_start();
226
        if ($result_domains) { ?>
227
            <strong><u>Domains</u></strong><BR><?php
228
            foreach ($result_domains as $row_domains) {
229
                if ($row_domains->expiry_date < $timestamp_basic) { ?>
230
231
                    <font color="#CC0000"><?php echo $row_domains->expiry_date; ?></font>&nbsp;&nbsp;<a
232
                        href="<?php echo $full_url; ?>/edit/domain.php?did=<?php echo $row_domains->id;
233
                        ?>"><?php echo $row_domains->domain; ?></a>&nbsp;&nbsp;<font
234
                        color="#CC0000">*EXPIRED*</font><BR><?php
235
                } else { ?>
236
237
                    <?php echo $row_domains->expiry_date; ?>&nbsp;&nbsp;<a href="<?php echo $full_url;
238
                    ?>/edit/domain.php?did=<?php echo $row_domains->id; ?>"><?php echo $row_domains->domain;
239
                        ?></a><BR><?php
240
                }
241
            }
242
        }
243
        return ob_get_clean();
244
    }
245
246
    public function showDomainsText($result_domains, $timestamp_basic)
247
    {
248
        $message = '';
249
        if ($result_domains) {
250
            $message .= "[DOMAINS]\n";
251
            foreach ($result_domains as $row_domains) {
252
                if ($row_domains->expiry_date < $timestamp_basic) {
253
                    $message .= $row_domains->expiry_date . " - " . $row_domains->domain . " *EXPIRED*\n";
254
                } else {
255
                    $message .= $row_domains->expiry_date . " - " . $row_domains->domain . "\n";
256
                }
257
            }
258
            $message .= "\n";
259
        }
260
        return $message;
261
    }
262
263
    public function showSslHtml($result_ssl, $full_url, $timestamp_basic)
264
    {
265
        ob_start();
266
        if ($result_ssl) { ?>
267
            <BR><strong><u>SSL Certificates</u></strong><BR><?php
268
            foreach ($result_ssl as $row_ssl) {
269
                if ($row_ssl->expiry_date < $timestamp_basic) { ?>
270
                    <font color="#CC0000"><?php echo $row_ssl->expiry_date; ?></font>&nbsp;&nbsp;<a
271
                        href="<?php echo $full_url; ?>/edit/ssl-cert.php?sslcid=<?php echo $row_ssl->id;
272
                        ?>"><?php echo $row_ssl->name; ?> (<?php echo $row_ssl->type; ?>)</a>&nbsp;&nbsp;<font
273
                        color="#CC0000">*EXPIRED*</font><BR><?php
274
                } else { ?>
275
                    <?php echo $row_ssl->expiry_date; ?>&nbsp;&nbsp;<a href="<?php echo $full_url;
276
                    ?>/edit/ssl-cert.php?sslcid=<?php echo $row_ssl->id; ?>"><?php echo $row_ssl->name; ?>
277
                        (<?php echo $row_ssl->type; ?>)</a><BR><?php
278
                }
279
            }
280
        }
281
        return ob_get_clean();
282
    }
283
284
    public function showSslText($result_ssl, $timestamp_basic)
285
    {
286
        $message = '';
287
        if ($result_ssl) {
288
            $message .= "[SSL CERTIFICATES]\n";
289
            foreach ($result_ssl as $row_ssl) {
290
                if ($row_ssl->expiry_date < $timestamp_basic) {
291
                    $message .= $row_ssl->expiry_date . " - " . $row_ssl->name . " (" . $row_ssl->type . ") *EXPIRED*\n";
292
                } else {
293
                    $message .= $row_ssl->expiry_date . " - " . $row_ssl->name . " (" . $row_ssl->type . ")\n";
294
                }
295
            }
296
            $message .= "\n";
297
        }
298
        return $message;
299
    }
300
301
    public function messageBottomHtml($full_url)
302
    {
303
        ob_start(); ?>
304
        <BR>Best Regards,<BR><BR>Greg Chetcuti<BR><a
305
            target="_blank" href="mailto:[email protected]">[email protected]</a><BR>
306
        </font>
307
        </td></tr>
308
        </table>
309
        <table width="575" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF"><tr>
310
        <td width="100%"><font color="#000000" size="2" face="Verdana, Arial, Helvetica, sans-serif">
311
        <BR><hr width="100%" size="2" noshade>You've received this email because you're currently subscribed to receive
312
        expiration notifications from the <?php echo SOFTWARE_TITLE; ?> installation located at: <a target="_blank"
313
        href="<?php echo $full_url; ?>/"><?php echo $full_url; ?>/</a><BR><BR>To unsubscribe from these notifications
314
        please visit: <BR><a target="_blank" href="<?php echo $full_url; ?>/settings/email/"><?php echo $full_url;
315
        ?>/settings/email/</a><BR><BR></font>
316
        </td></tr>
317
        </table>
318
        </body>
319
        </html><?php
320
        return ob_get_clean();
321
    }
322
323
    public function messageBottomText($full_url)
324
    {
325
        $message = '';
326
        $message .= "Best Regards,\n";
327
        $message .= "\n";
328
        $message .= "Greg Chetcuti\n";
329
        $message .= "[email protected]\n\n";
330
        $message .= "---\n\n";
331
        $message .= "You've received this email because you're currently subscribed to receive expiration notifications from the " . SOFTWARE_TITLE . " installation located at: " . $full_url . "\n\n";
332
        $message .= "To unsubscribe from these notifications please visit: " . $full_url . "/settings/email/";
333
        return $message;
334
    }
335
336
} //@formatter:on
337