Completed
Push — development ( a1bf21...cffa7e )
by Thomas
06:32 queued 06:13
created

runwatch.php ➔ insert_recommendation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 3
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
#!/usr/local/bin/php -q
2
<?php
3
/***************************************************************************
4
 * For license information see LICENSE.md
5
 * Ggf. muss die Location des php-Binaries angepasst werden.
6
 * Dieses Script sucht nach neuen Logs und Caches, die von Usern beobachtet
7
 * werden und verschickt dann die Emails.
8
 ***************************************************************************/
9
10
// needs absolute rootpath because called as cronjob
11
$rootpath = __DIR__ . '/../../';
12
require_once __DIR__ . '/../../lib/clicompatbase.inc.php';
13
require_once __DIR__ . '/../../lib2/translate.class.php';
14
require_once __DIR__ . '/settings.inc.php';
15
require_once __DIR__ . '/../../lib/consts.inc.php';
16
require_once __DIR__ . '/../../lib2/edithelper.inc.php';
17
require_once __DIR__ . '/../../lib2/logic/logtypes.inc.php';
18
19
if (!Cronjobs::enabled()) {
20
    exit;
21
}
22
23
// use posix pid-files to lock process
24
if (!CreatePidFile($watchpid)) {
25
    CleanupAndExit($watchpid, 'Another instance is running!');
0 ignored issues
show
Documentation introduced by
'Another instance is running!' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
26
    exit;
27
}
28
29
if (!function_exists('get_logtype_name')) {
30
    function get_logtype_name($logtype, $language)
0 ignored issues
show
Best Practice introduced by
The function get_logtype_name() has been defined more than once; this definition is ignored, only the first definition in htdocs/lib/common.inc.php (L800-809) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
31
    {
32
        return sqlValue(
33
            "SELECT IFNULL(`stt`.`text`, `log_types`.`en`)
34
         FROM `log_types`
35
         LEFT JOIN `sys_trans_text` `stt` ON `stt`.`trans_id`=`log_types`.`trans_id`
36
         AND `stt`.`lang`='" . sql_escape($language) . "'
37
         WHERE `log_types`.`id`='" . sql_escape($logtype) . "'",
38
            ''
39
        );
40
    }
41
}
42
43
$sDateformat = 'Y-m-d H:i:s';
44
db_connect();
45
if ($dblink === false) {
46
    echo 'Unable to connect to database';
47
    exit;
48
}
49
50
/* begin owner notifies */
51
$rsNewLogs = sql(
52
    'SELECT cache_logs.id log_id, caches.user_id user_id
53
    FROM cache_logs, caches
54
    WHERE cache_logs.cache_id=caches.cache_id
55
    AND cache_logs.owner_notified=0'
56
);
57
$mysqlNumRows = mysql_num_rows($rsNewLogs);
58
for ($i = 0; $i < $mysqlNumRows; $i++) {
59
    $rNewLog = sql_fetch_array($rsNewLogs);
60
61
    $rsNotified = sql(
62
        "SELECT `id`
63
        FROM watches_notified
64
        WHERE user_id='&1'
65
        AND object_id='&2'
66
        AND object_type=1",
67
        $rNewLog['user_id'],
68
        $rNewLog['log_id']
69
    );
70
    if (mysql_num_rows($rsNotified) === 0) {
71
        // Benachrichtigung speichern
72
        sql(
73
            "INSERT IGNORE INTO `watches_notified` (`user_id`, `object_id`, `object_type`, `date_created`)
74
            VALUES ('&1', '&2', 1, NOW())",
75
            $rNewLog['user_id'],
76
            $rNewLog['log_id']
77
        );
78
79
        // Owner notifications are always sent, independent of user.email_problems counter.
80
        process_owner_log($rNewLog['user_id'], $rNewLog['log_id']);
81
    }
82
    mysql_free_result($rsNotified);
83
84
    sql("UPDATE cache_logs SET owner_notified=1 WHERE id='&1'", $rNewLog['log_id']);
85
}
86
mysql_free_result($rsNewLogs);
87
/* end owner notifies */
88
89
/* begin cache_watches */
90
$rscw = sql(
91
    'SELECT `watches_logqueue`.`log_id`, `watches_logqueue`.`user_id`, `cache_logs`.`cache_id`
92
     FROM `watches_logqueue`
93
     INNER JOIN `cache_logs` ON `watches_logqueue`.`log_id`=`cache_logs`.`id`'
94
);
95
while ($rcw = mysql_fetch_assoc($rscw)) {
96
    // Benachrichtigung speichern
97
    sql(
98
        "INSERT IGNORE INTO `watches_notified` (`user_id`, `object_id`, `object_type`, `date_created`)
99
        VALUES ('&1', '&2', 1, NOW())",
100
        $rcw['user_id'],
101
        $rcw['log_id']
102
    );
103
104
    // Throttle email sending after undeliverable mails. See also runwatch.php.
105
    // See also stored procedure sp_notify_new_cache().
106
    // See http://forum.opencaching.de/index.php?topic=3123.0 on AOL.
107
    if (sqlValue(
108
        "SELECT `email_problems` = 0 OR DATEDIFF(NOW(),`last_email_problem`) > 1+DATEDIFF(`last_email_problem`,
109
                `first_email_problem`)
110
         FROM `user` WHERE `user_id`='" . sql_escape($rcw['user_id']) . "'",
111
        1
112
    )) {
113
        process_log_watch($rcw['user_id'], $rcw['log_id']);
114
    }
115
116
    sql("DELETE FROM `watches_logqueue` WHERE `log_id`='&1' AND `user_id`='&2'", $rcw['log_id'], $rcw['user_id']);
117
}
118
mysql_free_result($rscw);
119
/* end cache_watches */
120
121
/* begin send out everything that has to be sent */
122
123
$email_headers = 'From: "' . $mailfrom . '" <' . $mailfrom . '>';
124
125
$rsUsers = sql(
126
    "SELECT
127
        `user`.`user_id`,
128
        `user`.`username`,
129
        `user`.`email`,
130
        `user`.`watchmail_mode`,
131
        `user`.`watchmail_hour`,
132
        `user`.`watchmail_day`,
133
        `user`.`watchmail_nextmail`,
134
        IFNULL(`user`.`language`,'&1') `language`,
135
        `domain`
136
    FROM `user`
137
    INNER JOIN `watches_waiting`
138
        ON `user`.`user_id`=`watches_waiting`.`user_id`
139
    WHERE `user`.`watchmail_nextmail`<NOW()",
140
    $opt['template']['default']['locale']
141
);
142
$mysqlNumRows = mysql_num_rows($rsUsers);
143
for ($i = 0; $i < $mysqlNumRows; $i++) {
144
    $rUser = sql_fetch_array($rsUsers);
145
146
    if ($rUser['watchmail_nextmail'] != '0000-00-00 00:00:00') {
147
        $nologs = $translate->t('No new log entries.', '', basename(__FILE__), __LINE__, '', 1, $rUser['language']);
148
149
        $rsWatches = sql("SELECT COUNT(*) count FROM watches_waiting WHERE user_id='&1'", $rUser['user_id']);
150
        if (mysql_num_rows($rsWatches) > 0) {
151
            $r = sql_fetch_array($rsWatches);
152
            if ($r['count'] > 0) {
153
                // ok, eine mail ist fäig
154
                $mailbody = fetch_email_template('watchlist', $rUser['language'], $rUser['domain']);
155
                $mailbody = mb_ereg_replace('{username}', $rUser['username'], $mailbody);
156
157
                $rsWatchesOwner = sql(
158
                    "SELECT id, watchtext
159
                    FROM watches_waiting
160
                    WHERE user_id='&1'
161
                    AND watchtype=1
162
                    ORDER BY id DESC",
163
                    $rUser['user_id']
164
                );
165 View Code Duplication
                if (mysql_num_rows($rsWatchesOwner) > 0) {
166
                    $logtexts = '';
167
                    $mysqlNumRowsWatchesOwner = mysql_num_rows($rsWatchesOwner);
168
                    for ($j = 0; $j < $mysqlNumRowsWatchesOwner; $j++) {
169
                        $rWatch = sql_fetch_array($rsWatchesOwner);
170
                        $logtexts .= $rWatch['watchtext'];
171
                    }
172
173
                    while ((mb_substr($logtexts, -1) == "\n") || (mb_substr($logtexts, -1) == "\r")) {
174
                        $logtexts = mb_substr($logtexts, 0, mb_strlen($logtexts) - 1);
175
                    }
176
177
                    $mailbody = mb_ereg_replace('{ownerlogs}', $logtexts, $mailbody);
178
                } else {
179
                    $mailbody = mb_ereg_replace('{ownerlogs}', $nologs, $mailbody);
180
                }
181
                mysql_free_result($rsWatchesOwner);
182
183
                $rsWatchesLog = sql(
184
                    "SELECT id, watchtext
185
                    FROM watches_waiting
186
                    WHERE user_id='&1'
187
                    AND watchtype = 2
188
                    ORDER BY id DESC",
189
                    $rUser['user_id']
190
                );
191 View Code Duplication
                if (mysql_num_rows($rsWatchesLog) > 0) {
192
                    $logtexts = '';
193
                    $mysqlNumRowsWatchesLog = mysql_num_rows($rsWatchesLog);
194
                    for ($j = 0; $j < $mysqlNumRowsWatchesLog; $j++) {
195
                        $rWatch = sql_fetch_array($rsWatchesLog);
196
                        $logtexts .= $rWatch['watchtext'];
197
                    }
198
199
                    while ((mb_substr($logtexts, -1) == "\n") || (mb_substr($logtexts, -1) == "\r")) {
200
                        $logtexts = mb_substr($logtexts, 0, mb_strlen($logtexts) - 1);
201
                    }
202
203
                    $mailbody = mb_ereg_replace('{watchlogs}', $logtexts, $mailbody);
204
                } else {
205
                    $mailbody = mb_ereg_replace('{watchlogs}', $nologs, $mailbody);
206
                }
207
                mysql_free_result($rsWatchesLog);
208
209
                // mail versenden
210
                if ($debug == true) {
211
                    $mailadr = $debug_mailto;
212
                } else {
213
                    $mailadr = $rUser['email'];
214
                }
215
216
                if ($mailadr != '') {
217
                    if (is_existent_maildomain(getToMailDomain($mailadr))) {
218
                        $language = $rUser['language'] ? $rUser['language'] : $opt['template']['default']['locale'];
219
                        $mailsubject =
220
                            '[' . $maildomain . '] ' . $translate->t(
221
                                'Your watchlist of',
222
                                '',
223
                                basename(__FILE__),
224
                                __LINE__,
225
                                '',
226
                                1,
227
                                $language
228
                            ) . ' ' . date($opt['locale'][$language]['format']['phpdate']);
229
                        mb_send_mail($mailadr, $mailsubject, $mailbody, $email_headers);
230
231
                        // logentry($module, $eventid, $userid, $objectid1, $objectid2, $logtext, $details)
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
232
                        logentry('watchlist', 2, $rUser['user_id'], 0, 0, 'Sending mail to ' . $mailadr, []);
233
                    }
234
                }
235
236
                // entries entfernen
237
                sql("DELETE FROM watches_waiting WHERE user_id='&1' AND watchtype IN (1, 2)", $rUser['user_id']);
238
            }
239
        }
240
    }
241
242
    // Zeitpunkt der nästen Mail berechnen
243
    if ($rUser['watchmail_mode'] == 0) {
244
        $nextmail = date($sDateformat);
245 View Code Duplication
    } elseif ($rUser['watchmail_mode'] == 1) {
246
        $nextmail = date($sDateformat, mktime($rUser['watchmail_hour'], 0, 0, date('n'), date('j') + 1, date('Y')));
247
    } elseif ($rUser['watchmail_mode'] == 2) {
248
        $weekday = date('w');
249
        if ($weekday == 0) {
250
            $weekday = 7;
251
        }
252
253
        if ($weekday == $rUser['watchmail_day']) {
254
            $nextmail = date($sDateformat, mktime($rUser['watchmail_hour'], 0, 0, date('n'), date('j') + 7, date('Y')));
255
        } elseif ($weekday > $rUser['watchmail_day']) {
256
            $nextmail = date(
257
                $sDateformat,
258
                mktime(
259
                    $rUser['watchmail_hour'],
260
                    0,
261
                    0,
262
                    date('n'),
263
                    date('j') - $weekday + $rUser['watchmail_day'] + 7,
264
                    date('Y')
265
                )
266
            );
267 View Code Duplication
        } else {
268
            $nextmail = date(
269
                $sDateformat,
270
                mktime(
271
                    $rUser['watchmail_hour'],
272
                    0,
273
                    0,
274
                    date('n'),
275
                    date('j') + 6 - $rUser['watchmail_day'],
276
                    date('Y')
277
                )
278
            );
279
        }
280
    }
281
282
    sql("UPDATE user SET watchmail_nextmail='&1' WHERE user_id='&2'", $nextmail, $rUser['user_id']);
283
}
284
mysql_free_result($rsUsers);
285
286
/* cleanup */
287
288
// Discard old queue entries of users who disabled notifications.
289
// This is done *after* processing so nothing is lost on systems without
290
// periodical runwatch processing (e.g. developer systems).
291
// Do NOT move this into CleanupAndExit(), which may be run without processing!
292
293
sql('DELETE FROM `watches_waiting` WHERE DATEDIFF(NOW(),`date_created`) > 35');
294
295
CleanupAndExit($watchpid);
296
297
298
function process_owner_log($user_id, $log_id)
299
{
300
    global $opt, $dblink, $translate;
301
302
//    echo "process_owner_log($user_id, $log_id)\n";
303
304
    $rsLog = sql(
305
        "SELECT
306
            `cache_logs`.`cache_id`,
307
            `cache_logs`.`type`,
308
            `cache_logs`.`text`,
309
            `cache_logs`.`text_html`,
310
            `cache_logs`.`date` `logdate`,
311
            `cache_logs`.`needs_maintenance`,
312
            `cache_logs`.`listing_outdated`,
313
            `user`.`username`,
314
            `caches`.`name` `cachename`,
315
            `caches`.`wp_oc`,
316
            `cr`.`user_id` IS NOT NULL AS `recommendation`
317
        FROM `cache_logs`
318
        JOIN `user` ON `cache_logs`.`user_id`=`user`.`user_id`
319
        JOIN `caches` ON `cache_logs`.`cache_id`=`caches`.`cache_id`
320
        LEFT JOIN `cache_rating` `cr` ON
321
            `cr`.`cache_id`=`cache_logs`.`cache_id` AND
322
            `cr`.`rating_date`=`cache_logs`.`date` AND
323
            `cache_logs`.`type` IN (1,7)
324
        WHERE `cache_logs`.`id` ='&1'",
325
        $log_id
326
    );
327
    $rLog = sql_fetch_array($rsLog);
328
    mysql_free_result($rsLog);
329
330
    $logtext = html2plaintext($rLog['text'], $rLog['text_html'] == 0, EMAIL_LINEWRAP);
331
332
    $language = sqlValue("SELECT `language` FROM `user` WHERE `user_id`='" . sql_escape($user_id) . "'", null);
333
    if (!$language) {
334
        $language = $opt['template']['default']['locale'];
335
    }
336 View Code Duplication
    if (strpos($rLog['logdate'], '00:00:00') > 0) {
337
        $dateformat = $opt['locale'][$language]['format']['phpdate'];
338
    } else {
339
        $dateformat = $opt['locale'][$language]['format']['phpdatetime'];
340
    }
341
342
    $watchtext =
343
        '{date} ' . $translate->t(
344
            '{user} has logged your cache "{cachename}":',
345
            '',
346
            basename(__FILE__),
347
            __LINE__,
348
            '',
349
            1,
350
            $language
351
        ) . ' {action}{recommendation}{maintenance_flags}' . "\n" . '{shortlink_url}{wp_oc}' . "\n\n" . '{text}' . "\n\n\n\n";
352
353
    $watchtext = mb_ereg_replace('{date}', date($dateformat, strtotime($rLog['logdate'])), $watchtext);
354
    $watchtext = mb_ereg_replace('{wp_oc}', $rLog['wp_oc'], $watchtext);
355
    $watchtext = mb_ereg_replace('{text}', $logtext, $watchtext);
0 ignored issues
show
Security Code Execution introduced by
$logtext can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned in htdocs/lib2/html2text.class.php on line 450
  1. Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned
    in htdocs/lib2/html2text.class.php on line 450
  2. Tainted property html2text::$url is read, and html2text::$_link_list is assigned
    in htdocs/lib2/html2text.class.php on line 542
  3. Tainted property html2text::$_link_list is read, and $text is assigned
    in htdocs/lib2/html2text.class.php on line 498
  4. $text is passed through html_entity_decode(), and html2text::$text is assigned
    in htdocs/lib2/html2text.class.php on line 509
  5. Tainted property html2text::$text is read
    in htdocs/lib2/html2text.class.php on line 399
  6. html2text::get_text() returns tainted data, and $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 117
  7. $text is passed through str_replace()
    in htdocs/lib2/edithelper.inc.php on line 125
  8. $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 119
  9. html2plaintext() returns tainted data, and $logtext is assigned
    in htdocs/util/watchlist/runwatch.php on line 330
  2. Path: Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned in htdocs/lib2/html2text.class.php on line 452
  1. Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned
    in htdocs/lib2/html2text.class.php on line 452
  2. Tainted property html2text::$url is read, and html2text::$_link_list is assigned
    in htdocs/lib2/html2text.class.php on line 542
  3. Tainted property html2text::$_link_list is read, and $text is assigned
    in htdocs/lib2/html2text.class.php on line 498
  4. $text is passed through html_entity_decode(), and html2text::$text is assigned
    in htdocs/lib2/html2text.class.php on line 509
  5. Tainted property html2text::$text is read
    in htdocs/lib2/html2text.class.php on line 399
  6. html2text::get_text() returns tainted data, and $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 117
  7. $text is passed through str_replace()
    in htdocs/lib2/edithelper.inc.php on line 125
  8. $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 119
  9. html2plaintext() returns tainted data, and $logtext is assigned
    in htdocs/util/watchlist/runwatch.php on line 330

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
356
    $watchtext = mb_ereg_replace('{user}', $rLog['username'], $watchtext);
357
    $watchtext = mb_ereg_replace('{cachename}', $rLog['cachename'], $watchtext);
358
    $watchtext = mb_ereg_replace('{action}', get_logtype_name($rLog['type'], $language), $watchtext);
359
    $watchtext = insert_recommendation($rLog, $language, $watchtext);
360
    $watchtext = insert_maintenance_flags($rLog, $language, $watchtext);
361
362
    $domain = sqlValue("SELECT `domain` FROM `user` WHERE `user_id`='" . sql_escape($user_id) . "'", null);
363
    $urls = get_site_urls($domain);
364 View Code Duplication
    if ($urls['shortlink_url']) {
365
        $watchtext = mb_ereg_replace("{shortlink_url}", $urls['shortlink_url'], $watchtext);
366
    } else {
367
        $watchtext = mb_ereg_replace("{shortlink_url}", $urls['site_url'], $watchtext);
368
    }
369
370
    sql(
371
        "INSERT IGNORE INTO `watches_waiting`
372
         (`user_id`, `object_id`, `object_type`, `date_created`, `watchtext`, `watchtype`)
373
         VALUES ('&1', '&2', 1, NOW(), '&3', 1)",
374
        $user_id,
375
        $log_id,
376
        $watchtext
377
    );
378
379
    // logentry($module, $eventid, $userid, $objectid1, $objectid2, $logtext, $details)
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
380
    logentry('watchlist', 1, $user_id, $log_id, 0, $watchtext, []);
381
}
382
383
function process_log_watch($user_id, $log_id)
384
{
385
    global $opt, $dblink, $logwatch_text, $translate;
386
387
//    echo "process_log_watch($user_id, $log_id)\n";
388
389
    $rsLog = sql(
390
        "SELECT
391
            `cache_logs`.`cache_id`,
392
            `cache_logs`.`type`,
393
            `cache_logs`.`text`,
394
            `cache_logs`.`text_html`,
395
            `cache_logs`.`date` `logdate`,
396
            `cache_logs`.`needs_maintenance`,
397
            `cache_logs`.`listing_outdated`,
398
            `user`.`username`,
399
            `caches`.`name` `cachename`,
400
            `caches`.`wp_oc`,
401
            `cr`.`user_id` IS NOT NULL AS `recommendation`
402
        FROM `cache_logs`
403
        JOIN `user` ON `cache_logs`.`user_id`=`user`.`user_id`
404
        JOIN `caches` ON `cache_logs`.`cache_id`=`caches`.`cache_id`
405
        LEFT JOIN `cache_rating` `cr` ON
406
            `cr`.`cache_id`=`cache_logs`.`cache_id` AND
407
            `cr`.`rating_date`=`cache_logs`.`date` AND
408
            `cache_logs`.`type` IN (1,7)
409
        WHERE
410
            `cache_logs`.`user_id`=`user`.`user_id` AND
411
            `cache_logs`.`cache_id`=`caches`.`cache_id` AND
412
            `cache_logs`.`id` = '&1'",
413
        $log_id
414
    );
415
    $rLog = sql_fetch_array($rsLog);
416
    mysql_free_result($rsLog);
417
418
    $logtext = html2plaintext($rLog['text'], $rLog['text_html'] == 0, EMAIL_LINEWRAP);
419
420
    $language = sqlValue("SELECT `language` FROM `user` WHERE `user_id`='" . sql_escape($user_id) . "'", null);
421
    if (!$language) {
422
        $language = $opt['template']['default']['locale'];
423
    }
424 View Code Duplication
    if (strpos($rLog['logdate'], '00:00:00') > 0) {
425
        $dateformat = $opt['locale'][$language]['format']['phpdate'];
426
    } else {
427
        $dateformat = $opt['locale'][$language]['format']['phpdatetime'];
428
    }
429
430
    $watchtext =
431
        '{date} ' . $translate->t(
432
            '{user} has logged the cache "{cachename}":',
433
            '',
434
            basename(__FILE__),
435
            __LINE__,
436
            '',
437
            1,
438
            $language
439
        ) . ' {action}{recommendation}{maintenance_flags}' . "\n" . '{shortlink_url}{wp_oc}' . "\n{cachelists}\n" . '{text}' . "\n\n\n\n";
440
441
    $watchtext = mb_ereg_replace('{date}', date($dateformat, strtotime($rLog['logdate'])), $watchtext);
442
    $watchtext = mb_ereg_replace('{wp_oc}', $rLog['wp_oc'], $watchtext);
443
    $watchtext = mb_ereg_replace('{text}', $logtext, $watchtext);
0 ignored issues
show
Security Code Execution introduced by
$logtext can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned in htdocs/lib2/html2text.class.php on line 450
  1. Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned
    in htdocs/lib2/html2text.class.php on line 450
  2. Tainted property html2text::$url is read, and html2text::$_link_list is assigned
    in htdocs/lib2/html2text.class.php on line 542
  3. Tainted property html2text::$_link_list is read, and $text is assigned
    in htdocs/lib2/html2text.class.php on line 498
  4. $text is passed through html_entity_decode(), and html2text::$text is assigned
    in htdocs/lib2/html2text.class.php on line 509
  5. Tainted property html2text::$text is read
    in htdocs/lib2/html2text.class.php on line 399
  6. html2text::get_text() returns tainted data, and $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 117
  7. $text is passed through str_replace()
    in htdocs/lib2/edithelper.inc.php on line 125
  8. $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 119
  9. html2plaintext() returns tainted data, and $logtext is assigned
    in htdocs/util/watchlist/runwatch.php on line 418
  2. Path: Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned in htdocs/lib2/html2text.class.php on line 452
  1. Fetching key HTTP_HOST from $_SERVER, and html2text::$url is assigned
    in htdocs/lib2/html2text.class.php on line 452
  2. Tainted property html2text::$url is read, and html2text::$_link_list is assigned
    in htdocs/lib2/html2text.class.php on line 542
  3. Tainted property html2text::$_link_list is read, and $text is assigned
    in htdocs/lib2/html2text.class.php on line 498
  4. $text is passed through html_entity_decode(), and html2text::$text is assigned
    in htdocs/lib2/html2text.class.php on line 509
  5. Tainted property html2text::$text is read
    in htdocs/lib2/html2text.class.php on line 399
  6. html2text::get_text() returns tainted data, and $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 117
  7. $text is passed through str_replace()
    in htdocs/lib2/edithelper.inc.php on line 125
  8. $text is assigned
    in htdocs/lib2/edithelper.inc.php on line 119
  9. html2plaintext() returns tainted data, and $logtext is assigned
    in htdocs/util/watchlist/runwatch.php on line 418

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
444
    $watchtext = mb_ereg_replace('{user}', $rLog['username'], $watchtext);
445
    $watchtext = mb_ereg_replace('{cachename}', $rLog['cachename'], $watchtext);
446
    $watchtext = mb_ereg_replace('{action}', get_logtype_name($rLog['type'], $language), $watchtext);
447
    $watchtext = insert_recommendation($rLog, $language, $watchtext);
448
    $watchtext = insert_maintenance_flags($rLog, $language, $watchtext);
449
450
    $rsLists = sql(
451
        "SELECT `name` FROM `cache_lists` cl
452
        JOIN `cache_list_watches` clw ON clw.`cache_list_id`=cl.`id` AND clw.`user_id`='&1'
453
        JOIN `cache_list_items` cli ON cli.`cache_list_id`=cl.`id` AND cli.`cache_id`='&2'
454
        ORDER BY `name`",
455
        $user_id,
456
        $rLog['cache_id']
457
    );
458
    $cachelist_names = sql_fetch_column($rsLists);
459
    switch (count($cachelist_names)) {
460
        case 0:
461
            $cachelists = '';
462
            break;
463 View Code Duplication
        case 1:
464
            $cachelists =
465
                $translate->t(
466
                    'Cache list:',
467
                    '',
468
                    basename(__FILE__),
469
                    __LINE__,
470
                    '',
471
                    1,
472
                    $language
473
                ) . ' ' . $cachelist_names[0] . "\n";
474
            break;
475 View Code Duplication
        default:
476
            $cachelists =
477
                $translate->t(
478
                    'Cache lists:',
479
                    '',
480
                    basename(__FILE__),
481
                    __LINE__,
482
                    '',
483
                    1,
484
                    $language
485
                ) . ' ' . implode(', ', $cachelist_names) . "\n";
486
    }
487
    $watchtext = mb_ereg_replace('{cachelists}', $cachelists, $watchtext);
488
489
    $domain = sqlValue("SELECT `domain` FROM `user` WHERE `user_id`='" . sql_escape($user_id) . "'", null);
490
    $urls = get_site_urls($domain);
491 View Code Duplication
    if ($urls['shortlink_url']) {
492
        $watchtext = mb_ereg_replace("{shortlink_url}", $urls['shortlink_url'], $watchtext);
493
    } else {
494
        $watchtext = mb_ereg_replace("{shortlink_url}", $urls['site_url'], $watchtext);
495
    }
496
497
    sql(
498
        "INSERT IGNORE INTO watches_waiting
499
            (`user_id`, `object_id`, `object_type`, `date_created`, `watchtext`, `watchtype`)
500
            VALUES ('&1', '&2', 1, NOW(), '&3', 2)",
501
        $user_id,
502
        $log_id,
503
        $watchtext
504
    );
505
}
506
507
function insert_recommendation($rLog, $language, $watchtext)
508
{
509
    global $translate;
510
511
    $rtext =
512
        $rLog['recommendation']
513
        ? ', ' . $translate->t('Recommendation', '', basename(__FILE__), __LINE__, '', 1, $language)
514
        : '';
515
    return mb_ereg_replace('{recommendation}', $rtext, $watchtext);
516
}
517
518
/**
519
 * @param string $watchtext
520
 */
521
function insert_maintenance_flags($rLog, $language, $watchtext)
522
{
523
    global $translate;
524
525
    $flags = [''];
526 View Code Duplication
    if ($rLog['needs_maintenance'] > 0) {
527
        if ($rLog['needs_maintenance'] == 2) {
528
            $mstate = 'geocache needs maintenance';
529
        } else {
530
            $mstate = 'geocache is ok';
531
        }
532
        $flags[] = $translate->t($mstate, '', basename(__FILE__), __LINE__, '', 1, $language);
533
    }
534 View Code Duplication
    if ($rLog['listing_outdated'] > 0) {
535
        if ($rLog['listing_outdated'] == 2) {
536
            $mstate = 'description is outdated';
537
        } else {
538
            $mstate = 'description is ok';
539
        }
540
        $flags[] = $translate->t($mstate, '', basename(__FILE__), __LINE__, '', 1, $language);
541
    }
542
    $flagtext = implode(', ', $flags);
543
544
    return mb_ereg_replace('{maintenance_flags}', $flagtext, $watchtext);
545
}
546
547
/**
548
 * @param string $domain
549
 */
550 View Code Duplication
function is_existent_maildomain($domain)
0 ignored issues
show
Best Practice introduced by
The function is_existent_maildomain() has been defined more than once; this definition is ignored, only the first definition in htdocs/util/notification/run_notify.php (L234-252) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
551
{
552
    $smtp_serverlist = [];
553
    $smtp_serverweight = [];
554
555
    if (getmxrr($domain, $smtp_serverlist, $smtp_serverweight) != 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...
556
        if (count($smtp_serverlist) > 0) {
557
            return true;
558
        }
559
    }
560
561
    // check if A exists
562
    $a = dns_get_record($domain, DNS_A);
563
    if (count($a) > 0) {
564
        return true;
565
    }
566
567
    return false;
568
}
569
570
571 View Code Duplication
function getToMailDomain($mail)
0 ignored issues
show
Best Practice introduced by
The function getToMailDomain() has been defined more than once; this definition is ignored, only the first definition in htdocs/util/notification/run_notify.php (L254-267) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
572
{
573
    if ($mail == '') {
574
        return '';
575
    }
576
577
    if (strrpos($mail, '@') === false) {
578
        $domain = 'localhost';
579
    } else {
580
        $domain = substr($mail, strrpos($mail, '@') + 1);
581
    }
582
583
    return $domain;
584
}
585
586
587
//
588
// checks if other instance is running, creates pid-file for locking
589
//
590
function CreatePidFile($PidFile)
591
{
592
    if (!CheckDaemon($PidFile)) {
593
        return false;
594
    }
595
596
    if (file_exists($PidFile)) {
597
        echo "Error: Pidfile (" . $PidFile . ") already present at " . __FILE__ . ":" . __LINE__ . "!\n";
598
599
        return false;
600
    } else {
601
        if ($pidfile = @fopen($PidFile, "w")) {
602
            fputs($pidfile, posix_getpid());
603
            fclose($pidfile);
604
605
            return true;
606
        } else {
607
            echo "can't create Pidfile $PidFile at " . __FILE__ . ":" . __LINE__ . "!\n";
608
609
            return false;
610
        }
611
    }
612
}
613
614
//
615
// checks if other instance of process is running..
616
//
617
function CheckDaemon($PidFile)
618
{
619
    if ($pidfile = @fopen($PidFile, 'rb')) {
620
        $pid_daemon = fgets($pidfile, 20);
621
        fclose($pidfile);
622
623
        $pid_daemon = (int) $pid_daemon;
624
625
        // process running?
626
        if (posix_kill($pid_daemon, 0)) {
627
            // yes, good bye
628
            echo "Error: process already running with pid=$pid_daemon!\n";
629
            false;
630
        } else {
631
            // no, remove pid_file
632
            echo 'process not running, removing old pid_file (' . $PidFile . ")\n";
633
            unlink($PidFile);
634
635
            return true;
636
        }
637
    } else {
638
        return true;
639
    }
640
}
641
642
//
643
// deletes pid-file
644
//
645
function CleanupAndExit($PidFile, $message = false)
646
{
647
    if ($pidfile = @fopen($PidFile, 'rb')) {
648
        $pid = fgets($pidfile, 20);
649
        fclose($pidfile);
650
        if ($pid == posix_getpid()) {
651
            unlink($PidFile);
652
        }
653
    } else {
654
        echo "Error: can't delete own pidfile (" . $PidFile . ") at " . __FILE__ . ":" . __LINE__ . "!\n";
655
    }
656
657
    if ($message) {
658
        echo $message . "\n";
659
    }
660
}
661