Completed
Push — master ( 7bef58...5c053f )
by Julito
25:30
created

MessageManager::sendMessageToAllUsersInCourse()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
c 0
b 0
f 0
nop 4
dl 0
loc 31
rs 8.439
nc 8
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\UserBundle\Entity\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, User. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use ChamiloSession as Session;
6
7
/**
8
 * Class MessageManager.
9
 *
10
 * This class provides methods for messages management.
11
 * Include/require it in your code to use its features.
12
 *
13
 * @package chamilo.library
14
 */
15
class MessageManager
16
{
17
    /**
18
     * Get count new messages for the current user from the database.
19
     *
20
     * @return int
21
     */
22
    public static function getCountNewMessages()
23
    {
24
        $userId = api_get_user_id();
25
        if (empty($userId)) {
26
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
27
        }
28
29
        static $count;
30
        if (!isset($count)) {
31
            $cacheAvailable = api_get_configuration_value('apc');
32
            if ($cacheAvailable === true) {
33
                $var = api_get_configuration_value('apc_prefix').'social_messages_unread_u_'.$userId;
34
                if (apcu_exists($var)) {
35
                    $count = apcu_fetch($var);
36
                } else {
37
                    $count = self::getCountNewMessagesFromDB($userId);
38
                    apcu_store($var, $count, 60);
39
                }
40
            } else {
41
                $count = self::getCountNewMessagesFromDB($userId);
42
            }
43
        }
44
45
        return $count;
46
    }
47
48
    /**
49
     * Gets the total number of messages, used for the inbox sortable table.
50
     *
51
     * @param bool $unread
52
     *
53
     * @return int
54
     */
55
    public static function getNumberOfMessages($unread = false)
56
    {
57
        $table = Database::get_main_table(TABLE_MESSAGE);
58
        if ($unread) {
59
            $condition_msg_status = ' msg_status = '.MESSAGE_STATUS_UNREAD.' ';
60
        } else {
61
            $condition_msg_status = ' msg_status IN('.MESSAGE_STATUS_NEW.','.MESSAGE_STATUS_UNREAD.') ';
62
        }
63
64
        $keyword = Session::read('message_search_keyword');
65
        $keywordCondition = '';
66
        if (!empty($keyword)) {
67
            $keyword = Database::escape_string($keyword);
68
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
69
        }
70
71
        $sql = "SELECT COUNT(id) as number_messages
72
                FROM $table
73
                WHERE $condition_msg_status AND
74
                    user_receiver_id=".api_get_user_id()."
75
                    $keywordCondition
76
                ";
77
        $result = Database::query($sql);
78
        $result = Database::fetch_array($result);
79
80
        return $result['number_messages'];
81
    }
82
83
    /**
84
     * Gets information about some messages, used for the inbox sortable table.
85
     *
86
     * @param int    $from
87
     * @param int    $number_of_items
88
     * @param string $column
89
     * @param string $direction
90
     *
91
     * @return array
92
     */
93
    public static function get_message_data(
94
        $from,
95
        $number_of_items,
96
        $column,
97
        $direction,
98
        $userId = 0
99
    ) {
100
        $from = (int) $from;
101
        $number_of_items = (int) $number_of_items;
102
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
103
104
        //forcing this order
105
        if (!isset($direction)) {
106
            $column = 2;
107
            $direction = 'DESC';
108
        } else {
109
            $column = intval($column);
110
            if (!in_array($direction, ['ASC', 'DESC'])) {
111
                $direction = 'ASC';
112
            }
113
        }
114
115
        if (!in_array($column, [0, 1, 2])) {
116
            $column = 2;
117
        }
118
119
        $keyword = Session::read('message_search_keyword');
120
        $keywordCondition = '';
121
        if (!empty($keyword)) {
122
            $keyword = Database::escape_string($keyword);
123
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
124
        }
125
126
        $table = Database::get_main_table(TABLE_MESSAGE);
127
        $sql = "SELECT 
128
                    id as col0, 
129
                    title as col1, 
130
                    send_date as col2, 
131
                    msg_status as col3,
132
                    user_sender_id
133
                FROM $table
134
                WHERE
135
                    user_receiver_id=".$userId." AND
136
                    msg_status IN (".MESSAGE_STATUS_NEW.", ".MESSAGE_STATUS_UNREAD.")
137
                    $keywordCondition
138
                ORDER BY col$column $direction
139
                LIMIT $from, $number_of_items";
140
141
        $result = Database::query($sql);
142
        $message_list = [];
143
        $newMessageLink = api_get_path(WEB_CODE_PATH).'messages/new_message.php';
144
        while ($row = Database::fetch_array($result, 'ASSOC')) {
145
            $messageId = $row['col0'];
146
            $title = $row['col1'];
147
            $sendDate = $row['col2'];
148
            $status = $row['col3'];
149
            $senderId = $row['user_sender_id'];
150
151
            $title = Security::remove_XSS($title, STUDENT, true);
152
            $title = cut($title, 80, true);
153
154
            if ($status == 1) {
155
                $class = 'class = "unread"';
156
            } else {
157
                $class = 'class = "read"';
158
            }
159
160
            $userInfo = api_get_user_info($senderId);
161
            if (!empty($senderId) && !empty($userInfo)) {
162
                $message[1] = '<a '.$class.' href="view_message.php?id='.$messageId.'">'.$title.'</a><br />';
163
                $message[1] .= $userInfo['complete_name_with_username'];
164
                $message[3] =
165
                    Display::url(
166
                        Display::returnFontAwesomeIcon('reply', 2),
167
                        $newMessageLink.'?re_id='.$messageId,
168
                        ['title' => get_lang('ReplyToMessage')]
169
                    );
170
            } else {
171
                $message[1] = '<a '.$class.' href="view_message.php?id='.$messageId.'">'.$title.'</a><br />';
172
                $message[1] .= get_lang('UnknownUser');
173
                $message[3] =
174
                    Display::url(
175
                        Display::returnFontAwesomeIcon('reply', 2),
176
                        '#',
177
                        ['title' => get_lang('ReplyToMessage')]
178
                    );
179
            }
180
181
            $message[0] = $messageId;
182
            $message[2] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
183
            $message[3] .=
184
                '&nbsp;&nbsp;'.
185
                Display::url(
186
                    Display::returnFontAwesomeIcon('share', 2),
187
                    $newMessageLink.'?forward_id='.$messageId,
188
                    ['title' => get_lang('ForwardMessage')]
189
                ).
190
                '&nbsp;&nbsp;<a title="'.addslashes(
191
                    get_lang('DeleteMessage')
192
                ).'" onclick="javascript:if(!confirm('."'".addslashes(
193
                    api_htmlentities(get_lang('ConfirmDeleteMessage'))
194
                )."'".')) return false;" href="inbox.php?action=deleteone&id='.$messageId.'">'.
195
                Display::returnFontAwesomeIcon('trash', 2).'</a>';
196
            foreach ($message as $key => $value) {
197
                $message[$key] = api_xml_http_response_encode($value);
198
            }
199
            $message_list[] = $message;
200
        }
201
202
        return $message_list;
203
    }
204
205
    /**
206
     * @param array  $aboutUserInfo
207
     * @param array  $fromUserInfo
208
     * @param string $subject
209
     * @param string $content
210
     *
211
     * @return bool
212
     */
213
    public static function sendMessageAboutUser(
214
        $aboutUserInfo,
215
        $fromUserInfo,
216
        $subject,
217
        $content
218
    ) {
219
        if (empty($aboutUserInfo) || empty($fromUserInfo)) {
220
            return false;
221
        }
222
223
        if (empty($fromUserInfo['id']) || empty($aboutUserInfo['id'])) {
224
            return false;
225
        }
226
227
        $table = Database::get_main_table(TABLE_MESSAGE);
228
        $now = api_get_utc_datetime();
229
        $params = [
230
            'user_sender_id' => $fromUserInfo['id'],
231
            'user_receiver_id' => $aboutUserInfo['id'],
232
            'msg_status' => MESSAGE_STATUS_CONVERSATION,
233
            'send_date' => $now,
234
            'title' => $subject,
235
            'content' => $content,
236
            'group_id' => 0,
237
            'parent_id' => 0,
238
            'update_date' => $now,
239
        ];
240
        $id = Database::insert($table, $params);
241
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
242
            return true;
243
        }
244
245
        return false;
246
    }
247
248
    /**
249
     * @param array $aboutUserInfo
250
     *
251
     * @return array
252
     */
253
    public static function getMessagesAboutUser($aboutUserInfo)
254
    {
255
        if (!empty($aboutUserInfo)) {
256
            $criteria = [
257
                'userReceiverId' => $aboutUserInfo['id'],
258
                'msgStatus' => MESSAGE_STATUS_CONVERSATION,
259
            ];
260
            $repo = Database::getManager()->getRepository('ChamiloCoreBundle:Message');
261
            $messages = $repo->findBy($criteria, ['sendDate' => 'DESC']);
262
263
            return $messages;
264
        }
265
266
        return [];
267
    }
268
269
    /**
270
     * Sends a message to a user/group.
271
     *
272
     * @param int    $receiver_user_id
273
     * @param string $subject
274
     * @param string $content
275
     * @param array  $file_attachments files array($_FILES) (optional)
276
     * @param array  $file_comments    about attachment files (optional)
277
     * @param int    $group_id         (optional)
278
     * @param int    $parent_id        (optional)
279
     * @param int    $editMessageId    id for updating the message (optional)
280
     * @param int    $topic_id         (optional) the default value is the current user_id
281
     * @param int    $sender_id
282
     * @param bool   $directMessage
283
     * @param int    $forwardId
284
     * @param array  $smsParameters
285
     *
286
     * @return bool
287
     */
288
    public static function send_message(
289
        $receiver_user_id,
290
        $subject,
291
        $content,
292
        array $file_attachments = [],
293
        array $file_comments = [],
294
        $group_id = 0,
295
        $parent_id = 0,
296
        $editMessageId = 0,
297
        $topic_id = 0,
298
        $sender_id = 0,
299
        $directMessage = false,
300
        $forwardId = 0,
0 ignored issues
show
Unused Code introduced by
The parameter $forwardId is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

300
        /** @scrutinizer ignore-unused */ $forwardId = 0,

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

Loading history...
301
        $smsParameters = []
302
    ) {
303
        $table = Database::get_main_table(TABLE_MESSAGE);
304
        $group_id = (int) $group_id;
305
        $receiver_user_id = (int) $receiver_user_id;
306
        $parent_id = (int) $parent_id;
307
        $editMessageId = (int) $editMessageId;
308
        $topic_id = (int) $topic_id;
309
310
        if (!empty($receiver_user_id)) {
311
            $receiverUserInfo = api_get_user_info($receiver_user_id);
312
313
            // Disabling messages for inactive users.
314
            if ($receiverUserInfo['active'] == 0) {
315
                return false;
316
            }
317
        }
318
319
        $user_sender_id = empty($sender_id) ? api_get_user_id() : (int) $sender_id;
320
        if (empty($user_sender_id)) {
321
            Display::addFlash(Display::return_message(get_lang('UserDoesNotExist'), 'warning'));
322
323
            return false;
324
        }
325
326
        $totalFileSize = 0;
327
        if (is_array($file_attachments)) {
328
            foreach ($file_attachments as $file_attach) {
329
                $fileSize = isset($file_attach['size']) ? $file_attach['size'] : 0;
330
                if (is_array($fileSize)) {
331
                    foreach ($fileSize as $size) {
332
                        $totalFileSize += $size;
333
                    }
334
                } else {
335
                    $totalFileSize += $fileSize;
336
                }
337
            }
338
        }
339
340
        // Validating fields
341
        if (empty($subject) && empty($group_id)) {
342
            Display::addFlash(
343
                Display::return_message(
344
                    get_lang('YouShouldWriteASubject'),
345
                    'warning'
346
                )
347
            );
348
349
            return false;
350
        } elseif ($totalFileSize > intval(api_get_setting('message_max_upload_filesize'))) {
351
            $warning = sprintf(
352
                get_lang("FilesSizeExceedsX"),
353
                format_file_size(api_get_setting('message_max_upload_filesize'))
354
            );
355
356
            Display::addFlash(Display::return_message($warning, 'warning'));
357
358
            return false;
359
        }
360
361
        // Just in case we replace the and \n and \n\r while saving in the DB
362
        // $content = str_replace(array("\n", "\n\r"), '<br />', $content);
363
        $now = api_get_utc_datetime();
364
        if (!empty($receiver_user_id) || !empty($group_id)) {
365
            // message for user friend
366
            //@todo it's possible to edit a message? yes, only for groups
367
            if (!empty($editMessageId)) {
368
                $query = " UPDATE $table SET
369
                                update_date = '".$now."',
370
                                content = '".Database::escape_string($content)."'
371
                           WHERE id = '$editMessageId' ";
372
                Database::query($query);
373
                $messageId = $editMessageId;
374
            } else {
375
                $params = [
376
                    'user_sender_id' => $user_sender_id,
377
                    'user_receiver_id' => $receiver_user_id,
378
                    'msg_status' => MESSAGE_STATUS_UNREAD,
379
                    'send_date' => $now,
380
                    'title' => $subject,
381
                    'content' => $content,
382
                    'group_id' => $group_id,
383
                    'parent_id' => $parent_id,
384
                    'update_date' => $now,
385
                ];
386
                $messageId = Database::insert($table, $params);
387
            }
388
389
            // Save attachment file for inbox messages
390
            if (is_array($file_attachments)) {
391
                $i = 0;
392
                foreach ($file_attachments as $file_attach) {
393
                    if ($file_attach['error'] == 0) {
394
                        self::saveMessageAttachmentFile(
395
                            $file_attach,
396
                            isset($file_comments[$i]) ? $file_comments[$i] : null,
397
                            $messageId,
398
                            null,
399
                            $receiver_user_id,
400
                            $group_id
401
                        );
402
                    }
403
                    $i++;
404
                }
405
            }
406
407
            if (empty($group_id)) {
408
                // message in outbox for user friend or group
409
                $params = [
410
                    'user_sender_id' => $user_sender_id,
411
                    'user_receiver_id' => $receiver_user_id,
412
                    'msg_status' => MESSAGE_STATUS_OUTBOX,
413
                    'send_date' => $now,
414
                    'title' => $subject,
415
                    'content' => $content,
416
                    'group_id' => $group_id,
417
                    'parent_id' => $parent_id,
418
                    'update_date' => $now,
419
                ];
420
                $outbox_last_id = Database::insert($table, $params);
421
422
                // save attachment file for outbox messages
423
                if (is_array($file_attachments)) {
424
                    $o = 0;
425
                    foreach ($file_attachments as $file_attach) {
426
                        if ($file_attach['error'] == 0) {
427
                            $comment = isset($file_comments[$o]) ? $file_comments[$o] : '';
428
                            self::saveMessageAttachmentFile(
429
                                $file_attach,
430
                                $comment,
431
                                $outbox_last_id,
432
                                $user_sender_id
433
                            );
434
                        }
435
                        $o++;
436
                    }
437
                }
438
            }
439
440
            // Load user settings.
441
            $notification = new Notification();
442
            $sender_info = api_get_user_info($user_sender_id);
443
444
            // add file attachment additional attributes
445
            foreach ($file_attachments as $index => $file_attach) {
446
                $file_attachments[$index]['path'] = $file_attach['tmp_name'];
447
                $file_attachments[$index]['filename'] = $file_attach['name'];
448
            }
449
450
            if (empty($group_id)) {
451
                $type = Notification::NOTIFICATION_TYPE_MESSAGE;
452
                if ($directMessage) {
453
                    $type = Notification::NOTIFICATION_TYPE_DIRECT_MESSAGE;
454
                }
455
                $notification->saveNotification(
456
                    $messageId,
0 ignored issues
show
Bug introduced by
It seems like $messageId can also be of type false; however, parameter $messageId of Notification::saveNotification() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

456
                    /** @scrutinizer ignore-type */ $messageId,
Loading history...
457
                    $type,
458
                    [$receiver_user_id],
459
                    $subject,
460
                    $content,
461
                    $sender_info,
462
                    $file_attachments,
463
                    $smsParameters
464
                );
465
            } else {
466
                $usergroup = new UserGroup();
467
                $group_info = $usergroup->get($group_id);
468
                $group_info['topic_id'] = $topic_id;
469
                $group_info['msg_id'] = $messageId;
470
471
                $user_list = $usergroup->get_users_by_group(
472
                    $group_id,
473
                    false,
474
                    [],
475
                    0,
476
                    1000
477
                );
478
479
                // Adding more sense to the message group
480
                $subject = sprintf(get_lang('ThereIsANewMessageInTheGroupX'), $group_info['name']);
481
                $new_user_list = [];
482
                foreach ($user_list as $user_data) {
483
                    $new_user_list[] = $user_data['id'];
484
                }
485
                $group_info = [
486
                    'group_info' => $group_info,
487
                    'user_info' => $sender_info,
488
                ];
489
                $notification->saveNotification(
490
                    $messageId,
491
                    Notification::NOTIFICATION_TYPE_GROUP,
492
                    $new_user_list,
493
                    $subject,
494
                    $content,
495
                    $group_info,
496
                    $file_attachments,
497
                    $smsParameters
498
                );
499
            }
500
501
            return $messageId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $messageId also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
502
        }
503
504
        return false;
505
    }
506
507
    /**
508
     * @param int    $receiver_user_id
509
     * @param int    $subject
510
     * @param string $message
511
     * @param int    $sender_id
512
     * @param bool   $sendCopyToDrhUsers send copy to related DRH users
513
     * @param bool   $directMessage
514
     * @param array  $smsParameters
515
     * @param bool   $uploadFiles        Do not upload files using the MessageManager class
516
     * @param array  $attachmentList
517
     *
518
     * @return bool
519
     */
520
    public static function send_message_simple(
521
        $receiver_user_id,
522
        $subject,
523
        $message,
524
        $sender_id = 0,
525
        $sendCopyToDrhUsers = false,
526
        $directMessage = false,
527
        $smsParameters = [],
528
        $uploadFiles = true,
529
        $attachmentList = []
530
    ) {
531
        $files = $_FILES ? $_FILES : [];
532
        if ($uploadFiles === false) {
533
            $files = [];
534
        }
535
        // $attachmentList must have: tmp_name, name, size keys
536
        if (!empty($attachmentList)) {
537
            $files = $attachmentList;
538
        }
539
        $result = self::send_message(
540
            $receiver_user_id,
541
            $subject,
542
            $message,
543
            $files,
544
            [],
545
            null,
546
            null,
547
            null,
548
            null,
549
            $sender_id,
550
            $directMessage,
551
            0,
552
            $smsParameters
553
        );
554
555
        if ($sendCopyToDrhUsers) {
556
            $userInfo = api_get_user_info($receiver_user_id);
557
            $drhList = UserManager::getDrhListFromUser($receiver_user_id);
558
            if (!empty($drhList)) {
559
                foreach ($drhList as $drhInfo) {
560
                    $message = sprintf(
561
                        get_lang('CopyOfMessageSentToXUser'),
562
                        $userInfo['complete_name']
563
                    ).' <br />'.$message;
564
565
                    self::send_message_simple(
566
                        $drhInfo['user_id'],
567
                        $subject,
568
                        $message,
569
                        $sender_id,
570
                        false,
571
                        $directMessage
572
                    );
573
                }
574
            }
575
        }
576
577
        return $result;
578
    }
579
580
    /**
581
     * Update parent ids for other receiver user from current message in groups.
582
     *
583
     * @author Christian Fasanando Flores
584
     *
585
     * @param int $parent_id
586
     * @param int $receiver_user_id
587
     * @param int $messageId
588
     */
589
    public static function update_parent_ids_from_reply(
590
        $parent_id,
591
        $receiver_user_id,
592
        $messageId
593
    ) {
594
        $table = Database::get_main_table(TABLE_MESSAGE);
595
        $parent_id = intval($parent_id);
596
        $receiver_user_id = intval($receiver_user_id);
597
        $messageId = intval($messageId);
598
599
        // first get data from message id (parent)
600
        $sql = "SELECT * FROM $table WHERE id = '$parent_id'";
601
        $rs_message = Database::query($sql);
602
        $row_message = Database::fetch_array($rs_message);
603
604
        // get message id from data found early for other receiver user
605
        $sql = "SELECT id FROM $table
606
                WHERE
607
                    user_sender_id ='{$row_message['user_sender_id']}' AND
608
                    title='{$row_message['title']}' AND
609
                    content='{$row_message['content']}' AND
610
                    group_id='{$row_message['group_id']}' AND
611
                    user_receiver_id='$receiver_user_id'";
612
        $result = Database::query($sql);
613
        $row = Database::fetch_array($result);
614
615
        // update parent_id for other user receiver
616
        $sql = "UPDATE $table SET parent_id = ".$row['id']."
617
                WHERE id = $messageId";
618
        Database::query($sql);
619
    }
620
621
    /**
622
     * @param int $user_receiver_id
623
     * @param int $id
624
     *
625
     * @return bool
626
     */
627
    public static function delete_message_by_user_receiver($user_receiver_id, $id)
628
    {
629
        $table = Database::get_main_table(TABLE_MESSAGE);
630
        if ($id != strval(intval($id))) {
631
            return false;
632
        }
633
        $user_receiver_id = intval($user_receiver_id);
634
        $id = intval($id);
635
        $sql = "SELECT * FROM $table
636
                WHERE id = ".$id." AND msg_status <>".MESSAGE_STATUS_OUTBOX;
637
        $rs = Database::query($sql);
638
639
        if (Database::num_rows($rs) > 0) {
640
            // delete attachment file
641
            self::delete_message_attachment_file($id, $user_receiver_id);
642
            // delete message
643
            $query = "UPDATE $table 
644
                      SET msg_status = ".MESSAGE_STATUS_DELETED."
645
                      WHERE 
646
                        user_receiver_id=".$user_receiver_id." AND 
647
                        id = ".$id;
648
            Database::query($query);
649
650
            return true;
651
        } else {
652
            return false;
653
        }
654
    }
655
656
    /**
657
     * Set status deleted.
658
     *
659
     * @author Isaac FLores Paz <[email protected]>
660
     *
661
     * @param  int
662
     * @param  int
663
     *
664
     * @return bool
665
     */
666
    public static function delete_message_by_user_sender($user_sender_id, $id)
667
    {
668
        if ($id != strval(intval($id))) {
669
            return false;
670
        }
671
672
        $table = Database::get_main_table(TABLE_MESSAGE);
673
674
        $id = intval($id);
675
        $user_sender_id = intval($user_sender_id);
676
677
        $sql = "SELECT * FROM $table WHERE id='$id'";
678
        $rs = Database::query($sql);
679
680
        if (Database::num_rows($rs) > 0) {
681
            // delete attachment file
682
            self::delete_message_attachment_file($id, $user_sender_id);
683
            // delete message
684
            $sql = "UPDATE $table 
685
                    SET msg_status = ".MESSAGE_STATUS_DELETED."
686
                    WHERE user_sender_id='$user_sender_id' AND id='$id'";
687
            Database::query($sql);
688
689
            return true;
690
        }
691
692
        return false;
693
    }
694
695
    /**
696
     * Saves a message attachment files.
697
     *
698
     * @param array $file_attach $_FILES['name']
699
     * @param  string    a comment about the uploaded file
700
     * @param  int        message id
701
     * @param  int        receiver user id (optional)
702
     * @param  int        sender user id (optional)
703
     * @param  int        group id (optional)
704
     */
705
    public static function saveMessageAttachmentFile(
706
        $file_attach,
707
        $file_comment,
708
        $message_id,
709
        $receiver_user_id = 0,
710
        $sender_user_id = 0,
711
        $group_id = 0
712
    ) {
713
        $tbl_message_attach = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
714
715
        // Try to add an extension to the file if it hasn't one
716
        $type = isset($file_attach['type']) ? $file_attach['type'] : '';
717
        if (empty($type)) {
718
            $type = DocumentManager::file_get_mime_type($file_attach['name']);
719
        }
720
        $new_file_name = add_ext_on_mime(stripslashes($file_attach['name']), $type);
721
722
        // user's file name
723
        $file_name = $file_attach['name'];
724
        if (!filter_extension($new_file_name)) {
725
            Display::addFlash(Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'error'));
726
        } else {
727
            $new_file_name = uniqid('');
728
            if (!empty($receiver_user_id)) {
729
                $message_user_id = $receiver_user_id;
730
            } else {
731
                $message_user_id = $sender_user_id;
732
            }
733
734
            // User-reserved directory where photos have to be placed.*
735
            $userGroup = new UserGroup();
736
            if (!empty($group_id)) {
737
                $path_user_info = $userGroup->get_group_picture_path_by_id(
738
                    $group_id,
739
                    'system',
740
                    true
741
                );
742
            } else {
743
                $path_user_info['dir'] = UserManager::getUserPathById($message_user_id, 'system');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$path_user_info was never initialized. Although not strictly required by PHP, it is generally a good practice to add $path_user_info = array(); before regardless.
Loading history...
744
            }
745
746
            $path_message_attach = $path_user_info['dir'].'message_attachments/';
747
            // If this directory does not exist - we create it.
748
            if (!file_exists($path_message_attach)) {
749
                @mkdir($path_message_attach, api_get_permissions_for_new_directories(), true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

749
                /** @scrutinizer ignore-unhandled */ @mkdir($path_message_attach, api_get_permissions_for_new_directories(), true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
750
            }
751
752
            $new_path = $path_message_attach.$new_file_name;
753
754
            if (is_uploaded_file($file_attach['tmp_name'])) {
755
                @copy($file_attach['tmp_name'], $new_path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for copy(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

755
                /** @scrutinizer ignore-unhandled */ @copy($file_attach['tmp_name'], $new_path);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
756
            } else {
757
                // 'tmp_name' can be set by the ticket
758
                if (file_exists($file_attach['tmp_name'])) {
759
                    @copy($file_attach['tmp_name'], $new_path);
760
                }
761
            }
762
763
            // Storing the attachments if any
764
            $params = [
765
                'filename' => $file_name,
766
                'comment' => $file_comment,
767
                'path' => $new_file_name,
768
                'message_id' => $message_id,
769
                'size' => $file_attach['size'],
770
            ];
771
            Database::insert($tbl_message_attach, $params);
772
        }
773
    }
774
775
    /**
776
     * Delete message attachment files (logically updating the row with a suffix _DELETE_id).
777
     *
778
     * @param  int    message id
779
     * @param  int    message user id (receiver user id or sender user id)
780
     * @param  int    group id (optional)
781
     */
782
    public static function delete_message_attachment_file(
783
        $message_id,
784
        $message_uid,
785
        $group_id = 0
786
    ) {
787
        $message_id = intval($message_id);
788
        $message_uid = intval($message_uid);
789
        $table_message_attach = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
790
791
        $sql = "SELECT * FROM $table_message_attach 
792
                WHERE message_id = '$message_id'";
793
        $rs = Database::query($sql);
794
        while ($row = Database::fetch_array($rs)) {
795
            $path = $row['path'];
796
            $attach_id = $row['id'];
797
            $new_path = $path.'_DELETED_'.$attach_id;
798
799
            if (!empty($group_id)) {
800
                $userGroup = new UserGroup();
801
                $path_user_info = $userGroup->get_group_picture_path_by_id(
802
                    $group_id,
803
                    'system',
804
                    true
805
                );
806
            } else {
807
                $path_user_info['dir'] = UserManager::getUserPathById(
808
                    $message_uid,
809
                    'system'
810
                );
811
            }
812
813
            $path_message_attach = $path_user_info['dir'].'message_attachments/';
814
            if (is_file($path_message_attach.$path)) {
815
                if (rename($path_message_attach.$path, $path_message_attach.$new_path)) {
816
                    $sql = "UPDATE $table_message_attach set path='$new_path'
817
                            WHERE id ='$attach_id'";
818
                    Database::query($sql);
819
                }
820
            }
821
        }
822
    }
823
824
    /**
825
     * update messages by user id and message id.
826
     *
827
     * @param int $user_id
828
     * @param int $message_id
829
     *
830
     * @return bool
831
     */
832
    public static function update_message($user_id, $message_id)
833
    {
834
        if ($message_id != strval(intval($message_id)) || $user_id != strval(intval($user_id))) {
835
            return false;
836
        }
837
838
        $table = Database::get_main_table(TABLE_MESSAGE);
839
        $sql = "UPDATE $table SET 
840
                    msg_status = '".MESSAGE_STATUS_NEW."'
841
                WHERE
842
                    msg_status <> ".MESSAGE_STATUS_OUTBOX." AND
843
                    user_receiver_id = ".intval($user_id)." AND
844
                    id = '".intval($message_id)."'";
845
        Database::query($sql);
846
847
        return true;
848
    }
849
850
    /**
851
     * @param int    $user_id
852
     * @param int    $message_id
853
     * @param string $type
854
     *
855
     * @return bool
856
     */
857
    public static function update_message_status($user_id, $message_id, $type)
858
    {
859
        $type = intval($type);
860
        if ($message_id != strval(intval($message_id)) || $user_id != strval(intval($user_id))) {
861
            return false;
862
        }
863
        $table_message = Database::get_main_table(TABLE_MESSAGE);
864
        $sql = "UPDATE $table_message SET
865
                    msg_status = '$type'
866
                WHERE
867
                    user_receiver_id = ".intval($user_id)." AND
868
                    id = '".intval($message_id)."'";
869
        Database::query($sql);
870
    }
871
872
    /**
873
     * get messages by user id and message id.
874
     *
875
     * @param int $user_id
876
     * @param int $message_id
877
     *
878
     * @return array
879
     */
880
    public static function get_message_by_user($user_id, $message_id)
881
    {
882
        if ($message_id != strval(intval($message_id)) || $user_id != strval(intval($user_id))) {
883
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
884
        }
885
        $table = Database::get_main_table(TABLE_MESSAGE);
886
        $query = "SELECT * FROM $table
887
                  WHERE user_receiver_id=".intval($user_id)." AND id='".intval($message_id)."'";
888
        $result = Database::query($query);
889
890
        return $row = Database::fetch_array($result);
891
    }
892
893
    /**
894
     * get messages by group id.
895
     *
896
     * @param int $group_id group id
897
     *
898
     * @return array
899
     */
900
    public static function get_messages_by_group($group_id)
901
    {
902
        if ($group_id != strval(intval($group_id))) {
903
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
904
        }
905
906
        $table = Database::get_main_table(TABLE_MESSAGE);
907
        $group_id = intval($group_id);
908
        $sql = "SELECT * FROM $table
909
                WHERE
910
                    group_id= $group_id AND
911
                    msg_status NOT IN ('".MESSAGE_STATUS_OUTBOX."', '".MESSAGE_STATUS_DELETED."')
912
                ORDER BY id";
913
        $rs = Database::query($sql);
914
        $data = [];
915
        if (Database::num_rows($rs) > 0) {
916
            while ($row = Database::fetch_array($rs, 'ASSOC')) {
917
                $data[] = $row;
918
            }
919
        }
920
921
        return $data;
922
    }
923
924
    /**
925
     * get messages by group id.
926
     *
927
     * @param int $group_id
928
     * @param int $message_id
929
     *
930
     * @return array
931
     */
932
    public static function get_messages_by_group_by_message($group_id, $message_id)
933
    {
934
        if ($group_id != strval(intval($group_id))) {
935
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
936
        }
937
        $table = Database::get_main_table(TABLE_MESSAGE);
938
        $group_id = intval($group_id);
939
        $sql = "SELECT * FROM $table
940
                WHERE
941
                    group_id = $group_id AND
942
                    msg_status NOT IN ('".MESSAGE_STATUS_OUTBOX."', '".MESSAGE_STATUS_DELETED."')
943
                ORDER BY id ";
944
945
        $rs = Database::query($sql);
946
        $data = [];
947
        $parents = [];
948
        if (Database::num_rows($rs) > 0) {
949
            while ($row = Database::fetch_array($rs, 'ASSOC')) {
950
                if ($message_id == $row['parent_id'] || in_array($row['parent_id'], $parents)) {
951
                    $parents[] = $row['id'];
952
                    $data[] = $row;
953
                }
954
            }
955
        }
956
957
        return $data;
958
    }
959
960
    /**
961
     * Get messages by parent id optionally with limit.
962
     *
963
     * @param  int        parent id
964
     * @param  int        group id (optional)
965
     * @param  int        offset (optional)
966
     * @param  int        limit (optional)
967
     *
968
     * @return array
969
     */
970
    public static function get_messages_by_parent($parent_id, $group_id = 0, $offset = 0, $limit = 0)
971
    {
972
        if ($parent_id != strval(intval($parent_id))) {
973
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
974
        }
975
        $table = Database::get_main_table(TABLE_MESSAGE);
976
        $parent_id = intval($parent_id);
977
        $condition_group_id = '';
978
        if (!empty($group_id)) {
979
            $group_id = intval($group_id);
980
            $condition_group_id = " AND group_id = '$group_id' ";
981
        }
982
983
        $condition_limit = '';
984
        if ($offset && $limit) {
985
            $offset = ($offset - 1) * $limit;
986
            $condition_limit = " LIMIT $offset,$limit ";
987
        }
988
989
        $sql = "SELECT * FROM $table
990
                WHERE
991
                    parent_id='$parent_id' AND
992
                    msg_status <> ".MESSAGE_STATUS_OUTBOX."
993
                    $condition_group_id
994
                ORDER BY send_date DESC $condition_limit ";
995
        $rs = Database::query($sql);
996
        $data = [];
997
        if (Database::num_rows($rs) > 0) {
998
            while ($row = Database::fetch_array($rs)) {
999
                $data[$row['id']] = $row;
1000
            }
1001
        }
1002
1003
        return $data;
1004
    }
1005
1006
    /**
1007
     * Gets information about messages sent.
1008
     *
1009
     * @param  int
1010
     * @param  int
1011
     * @param  string
1012
     *
1013
     * @return array
1014
     */
1015
    public static function get_message_data_sent(
1016
        $from,
1017
        $number_of_items,
1018
        $column,
1019
        $direction
1020
    ) {
1021
        $from = intval($from);
1022
        $number_of_items = intval($number_of_items);
1023
        if (!isset($direction)) {
1024
            $column = 2;
1025
            $direction = 'DESC';
1026
        } else {
1027
            $column = intval($column);
1028
            if (!in_array($direction, ['ASC', 'DESC'])) {
1029
                $direction = 'ASC';
1030
            }
1031
        }
1032
1033
        if (!in_array($column, [0, 1, 2])) {
1034
            $column = 2;
1035
        }
1036
        $table = Database::get_main_table(TABLE_MESSAGE);
1037
        $request = api_is_xml_http_request();
1038
        $keyword = Session::read('message_sent_search_keyword');
1039
        $keywordCondition = '';
1040
        if (!empty($keyword)) {
1041
            $keyword = Database::escape_string($keyword);
1042
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
1043
        }
1044
1045
        $sql = "SELECT
1046
                    id as col0, 
1047
                    title as col1, 
1048
                    send_date as col2, 
1049
                    user_receiver_id, 
1050
                    msg_status,
1051
                    user_sender_id
1052
                FROM $table
1053
                WHERE
1054
                    user_sender_id = ".api_get_user_id()." AND
1055
                    msg_status = ".MESSAGE_STATUS_OUTBOX."
1056
                    $keywordCondition
1057
                ORDER BY col$column $direction
1058
                LIMIT $from, $number_of_items";
1059
        $result = Database::query($sql);
1060
        $i = 0;
1061
        $message_list = [];
1062
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1063
            $messageId = $row['col0'];
1064
            $title = $row['col1'];
1065
            $sendDate = $row['col2'];
1066
            $status = $row['msg_status'];
1067
            $senderId = $row['user_sender_id'];
1068
1069
            if ($request === true) {
1070
                $message[0] = '<input type="checkbox" value='.$messageId.' name="out[]">';
1071
            } else {
1072
                $message[0] = $messageId;
1073
            }
1074
1075
            $class = 'class = "read"';
1076
            $title = Security::remove_XSS($title);
1077
            $userInfo = api_get_user_info($senderId);
1078
            if ($request === true) {
1079
                $message[1] = '<a onclick="show_sent_message('.$messageId.')" href="javascript:void(0)">'.$userInfo['complete_name_with_username'].'</a>';
1080
                $message[2] = '<a onclick="show_sent_message('.$messageId.')" href="javascript:void(0)">'.str_replace("\\", "", $title).'</a>';
1081
                //date stays the same
1082
                $message[3] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
1083
                $message[4] = '&nbsp;&nbsp;<a title="'.addslashes(get_lang('DeleteMessage')).'" onclick="delete_one_message_outbox('.$messageId.')" href="javascript:void(0)"  >'.
1084
                    Display::returnFontAwesomeIcon('trash', 2).'</a>';
1085
            } else {
1086
                $message[1] = '<a '.$class.' onclick="show_sent_message('.$messageId.')" href="../messages/view_message.php?id_send='.$messageId.'">'.$title.'</a><br />'.$userInfo['complete_name_with_username'];
1087
                $message[2] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
1088
                $message[3] = '<a title="'.addslashes(get_lang('DeleteMessage')).'" href="outbox.php?action=deleteone&id='.$messageId.'"  onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmDeleteMessage')))."'".')) return false;" >'.
1089
                    Display::returnFontAwesomeIcon('trash', 2).'</a>';
1090
            }
1091
1092
            $message_list[] = $message;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.
Loading history...
1093
            $i++;
1094
        }
1095
1096
        return $message_list;
1097
    }
1098
1099
    /**
1100
     * Gets information about number messages sent.
1101
     *
1102
     * @author Isaac FLores Paz <[email protected]>
1103
     *
1104
     * @param void
1105
     *
1106
     * @return int
1107
     */
1108
    public static function getNumberOfMessagesSent()
1109
    {
1110
        $table = Database::get_main_table(TABLE_MESSAGE);
1111
        $keyword = Session::read('message_sent_search_keyword');
1112
        $keywordCondition = '';
1113
        if (!empty($keyword)) {
1114
            $keyword = Database::escape_string($keyword);
1115
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
1116
        }
1117
1118
        $sql = "SELECT COUNT(id) as number_messages 
1119
                FROM $table
1120
                WHERE
1121
                  msg_status = ".MESSAGE_STATUS_OUTBOX." AND
1122
                  user_sender_id = ".api_get_user_id()."
1123
                  $keywordCondition
1124
                ";
1125
        $result = Database::query($sql);
1126
        $result = Database::fetch_array($result);
1127
1128
        return $result['number_messages'];
1129
    }
1130
1131
    /**
1132
     * display message box in the inbox.
1133
     *
1134
     * @param int the message id
1135
     * @param string inbox or outbox strings are available
1136
     *
1137
     * @todo replace numbers with letters in the $row array pff...
1138
     *
1139
     * @return string html with the message content
1140
     */
1141
    public static function showMessageBox($messageId, $source = 'inbox')
1142
    {
1143
        $table = Database::get_main_table(TABLE_MESSAGE);
1144
        $messageId = intval($messageId);
1145
1146
        if ($source == 'outbox') {
1147
            if (isset($messageId) && is_numeric($messageId)) {
1148
                $query = "SELECT * FROM $table
1149
                          WHERE
1150
                            user_sender_id = ".api_get_user_id()." AND
1151
                            id = ".$messageId." AND
1152
                            msg_status = ".MESSAGE_STATUS_OUTBOX;
1153
                $result = Database::query($query);
1154
            }
1155
        } else {
1156
            if (is_numeric($messageId) && !empty($messageId)) {
1157
                $query = "UPDATE $table SET
1158
                          msg_status = '".MESSAGE_STATUS_NEW."'
1159
                          WHERE
1160
                            user_receiver_id=".api_get_user_id()." AND
1161
                            id='".$messageId."'";
1162
                Database::query($query);
1163
1164
                $query = "SELECT * FROM $table
1165
                          WHERE
1166
                            msg_status<> ".MESSAGE_STATUS_OUTBOX." AND
1167
                            user_receiver_id=".api_get_user_id()." AND
1168
                            id='".$messageId."'";
1169
                $result = Database::query($query);
1170
            }
1171
        }
1172
        $row = Database::fetch_array($result, 'ASSOC');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
1173
        $user_sender_id = $row['user_sender_id'];
1174
1175
        // get file attachments by message id
1176
        $files_attachments = self::get_links_message_attachment_files(
1177
            $messageId,
1178
            $source
1179
        );
1180
1181
        $row['content'] = str_replace('</br>', '<br />', $row['content']);
1182
        $title = Security::remove_XSS($row['title'], STUDENT, true);
1183
        $content = Security::remove_XSS($row['content'], STUDENT, true);
1184
1185
        $name = get_lang('UnknownUser');
1186
        $fromUser = api_get_user_info($user_sender_id);
1187
        $userImage = '';
1188
        if (!empty($user_sender_id) && !empty($fromUser)) {
1189
            $name = $fromUser['complete_name_with_username'];
1190
            $userImage = Display::img(
1191
                $fromUser['avatar_small'],
1192
                $name,
1193
                ['title' => $name, 'class' => 'img-responsive img-circle', 'style' => 'max-width:35px'],
1194
                false
1195
            );
1196
        }
1197
1198
        $message_content = Display::page_subheader(str_replace("\\", "", $title));
1199
1200
        $receiverUserInfo = [];
1201
        if (!empty($row['user_receiver_id'])) {
1202
            $receiverUserInfo = api_get_user_info($row['user_receiver_id']);
1203
        }
1204
1205
        $message_content .= '<tr>';
1206
        if (api_get_setting('allow_social_tool') == 'true') {
1207
            $message_content .= '<div class="row">';
1208
            if ($source == 'outbox') {
1209
                $message_content .= '<div class="col-md-12">';
1210
                $message_content .= '<ul class="list-message">';
1211
                $message_content .= '<li>'.$userImage.'</li>';
1212
                $message_content .= '<li>'.$name.'&nbsp;';
1213
                if (!empty($receiverUserInfo)) {
1214
                    $message_content .= api_strtolower(
1215
                            get_lang('To')
1216
                        ).'&nbsp;<b>'.$receiverUserInfo['complete_name_with_username'].'</b></li>';
1217
                } else {
1218
                    $message_content .= api_strtolower(get_lang('To')).'&nbsp;<b>-</b></li>';
1219
                }
1220
1221
                $message_content .= '<li>'.Display::dateToStringAgoAndLongDate($row['send_date']).'</li>';
1222
                $message_content .= '</ul>';
1223
                $message_content .= '</div>';
1224
            } else {
1225
                $message_content .= '<div class="col-md-12">';
1226
                $message_content .= '<ul class="list-message">';
1227
                if (!empty($user_sender_id)) {
1228
                    $message_content .= '<li>'.$userImage.'</li>';
1229
                    $message_content .= '<li><a href="'.api_get_path(
1230
                            WEB_PATH
1231
                        ).'main/social/profile.php?u='.$user_sender_id.'">'.$name.'</a>';
1232
                } else {
1233
                    $message_content .= '<li>'.$name;
1234
                }
1235
1236
                $message_content .= '&nbsp;'.api_strtolower(get_lang('To')).'&nbsp;'.get_lang('Me');
1237
                $message_content .= '<li>'.Display::dateToStringAgoAndLongDate($row['send_date']).'</li>';
1238
                $message_content .= '</ul>';
1239
                $message_content .= '</div>';
1240
            }
1241
            $message_content .= '</div>';
1242
        } else {
1243
            if ($source == 'outbox') {
1244
                $message_content .= get_lang('From').':&nbsp;'.$name.'</b> '.api_strtolower(get_lang('To')).' <b>'.
1245
                    $receiverUserInfo['complete_name_with_username'].'</b>';
1246
            } else {
1247
                $message_content .= get_lang('From').':&nbsp;'.$name.'</b> '.api_strtolower(get_lang('To')).' <b>'.
1248
                    get_lang('Me').'</b>';
1249
            }
1250
        }
1251
1252
        $message_content .= '		        
1253
		        <hr style="color:#ddd" />
1254
		        <table width="100%">
1255
		            <tr>
1256
		              <td valign=top class="view-message-content">'.str_replace("\\", "", $content).'</td>
1257
		            </tr>
1258
		        </table>
1259
		        <div id="message-attach">'.(!empty($files_attachments) ? implode('<br />', $files_attachments) : '').'</div>
1260
		        <div style="padding: 15px 0px 5px 0px">';
1261
        $social_link = '';
1262
        if (isset($_GET['f']) && $_GET['f'] == 'social') {
1263
            $social_link = 'f=social';
1264
        }
1265
        if ($source == 'outbox') {
1266
            $message_content .= '<a href="outbox.php?'.$social_link.'">'.
1267
                Display::return_icon('back.png', get_lang('ReturnToOutbox')).'</a> &nbsp';
1268
        } else {
1269
            $message_content .= '<a href="inbox.php?'.$social_link.'">'.
1270
                Display::return_icon('back.png', get_lang('ReturnToInbox')).'</a> &nbsp';
1271
            $message_content .= '<a href="new_message.php?re_id='.$messageId.'&'.$social_link.'">'.
1272
                Display::return_icon('message_reply.png', get_lang('ReplyToMessage')).'</a> &nbsp';
1273
        }
1274
        $message_content .= '<a href="inbox.php?action=deleteone&id='.$messageId.'&'.$social_link.'" >'.
1275
            Display::return_icon('delete.png', get_lang('DeleteMessage')).'</a>&nbsp';
1276
1277
        $message_content .= '</div></td>
1278
		      <td width=10></td>
1279
		    </tr>
1280
		</table>';
1281
1282
        return $message_content;
1283
    }
1284
1285
    /**
1286
     * get user id by user email.
1287
     *
1288
     * @param string $user_email
1289
     *
1290
     * @return int user id
1291
     */
1292
    public static function get_user_id_by_email($user_email)
1293
    {
1294
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1295
        $sql = 'SELECT user_id FROM '.$tbl_user.'
1296
                WHERE email="'.Database::escape_string($user_email).'";';
1297
        $rs = Database::query($sql);
1298
        $row = Database::fetch_array($rs, 'ASSOC');
1299
        if (isset($row['user_id'])) {
1300
            return $row['user_id'];
1301
        } else {
1302
            return null;
1303
        }
1304
    }
1305
1306
    /**
1307
     * Displays messages of a group with nested view.
1308
     *
1309
     * @param int $group_id
1310
     *
1311
     * @return string
1312
     */
1313
    public static function display_messages_for_group($group_id)
1314
    {
1315
        global $my_group_role;
1316
1317
        $rows = self::get_messages_by_group($group_id);
1318
        $topics_per_page = 10;
1319
        $html_messages = '';
1320
        $query_vars = ['id' => $group_id, 'topics_page_nr' => 0];
1321
1322
        if (is_array($rows) && count($rows) > 0) {
1323
            // prepare array for topics with its items
1324
            $topics = [];
1325
            $x = 0;
1326
            foreach ($rows as $index => $value) {
1327
                if (empty($value['parent_id'])) {
1328
                    $topics[$value['id']] = $value;
1329
                }
1330
            }
1331
1332
            $new_topics = [];
1333
1334
            foreach ($topics as $id => $value) {
1335
                $rows = null;
1336
                $rows = self::get_messages_by_group_by_message($group_id, $value['id']);
1337
                if (!empty($rows)) {
1338
                    $count = count(self::calculate_children($rows, $value['id']));
1339
                } else {
1340
                    $count = 0;
1341
                }
1342
                $value['count'] = $count;
1343
                $new_topics[$id] = $value;
1344
            }
1345
1346
            $array_html = [];
1347
            foreach ($new_topics as $index => $topic) {
1348
                $html = '';
1349
                // topics
1350
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1351
                $name = $user_sender_info['complete_name'];
1352
                $html .= '<div class="groups-messages">';
1353
                $html .= '<div class="row">';
1354
1355
                $items = $topic['count'];
1356
                $reply_label = ($items == 1) ? get_lang('GroupReply') : get_lang('GroupReplies');
1357
                $label = '<i class="fa fa-envelope"></i> '.$items.' '.$reply_label;
1358
                $topic['title'] = trim($topic['title']);
1359
1360
                if (empty($topic['title'])) {
1361
                    $topic['title'] = get_lang('Untitled');
1362
                }
1363
1364
                $html .= '<div class="col-xs-8 col-md-10">';
1365
                $html .= Display::tag(
1366
                    'h4',
1367
                    Display::url(
1368
                        Security::remove_XSS($topic['title'], STUDENT, true),
1369
                        api_get_path(WEB_CODE_PATH).'social/group_topics.php?id='.$group_id.'&topic_id='.$topic['id']
1370
                    ),
1371
                    ['class' => 'title']
1372
                );
1373
                $actions = '';
1374
                if ($my_group_role == GROUP_USER_PERMISSION_ADMIN ||
1375
                    $my_group_role == GROUP_USER_PERMISSION_MODERATOR
1376
                ) {
1377
                    $actions = '<br />'.Display::url(
1378
                            get_lang('Delete'),
1379
                            api_get_path(
1380
                                WEB_CODE_PATH
1381
                            ).'social/group_topics.php?action=delete&id='.$group_id.'&topic_id='.$topic['id'],
1382
                            ['class' => 'btn btn-default']
1383
                        );
1384
                }
1385
1386
                $date = '';
1387
                if ($topic['send_date'] != $topic['update_date']) {
1388
                    if (!empty($topic['update_date'])) {
1389
                        $date .= '<i class="fa fa-calendar"></i> '.get_lang(
1390
                                'LastUpdate'
1391
                            ).' '.Display::dateToStringAgoAndLongDate($topic['update_date']);
1392
                    }
1393
                } else {
1394
                    $date .= '<i class="fa fa-calendar"></i> '.get_lang(
1395
                            'Created'
1396
                        ).' '.Display::dateToStringAgoAndLongDate($topic['send_date']);
1397
                }
1398
                $html .= '<div class="date">'.$label.' - '.$date.$actions.'</div>';
1399
                $html .= '</div>';
1400
1401
                $image = $user_sender_info['avatar'];
1402
1403
                $user_info = '<div class="author"><img class="img-responsive img-circle" src="'.$image.'" alt="'.$name.'"  width="64" height="64" title="'.$name.'" /></div>';
1404
                $user_info .= '<div class="name"><a href="'.api_get_path(
1405
                        WEB_PATH
1406
                    ).'main/social/profile.php?u='.$topic['user_sender_id'].'">'.$name.'&nbsp;</a></div>';
1407
1408
                $html .= '<div class="col-xs-4 col-md-2">';
1409
                $html .= $user_info;
1410
                $html .= '</div>';
1411
                $html .= '</div>';
1412
                $html .= '</div>';
1413
1414
                $array_html[] = [$html];
1415
            }
1416
1417
            // grids for items and topics  with paginations
1418
            $html_messages .= Display::return_sortable_grid(
1419
                'topics',
1420
                [],
1421
                $array_html,
1422
                [
1423
                    'hide_navigation' => false,
1424
                    'per_page' => $topics_per_page,
1425
                ],
1426
                $query_vars,
1427
                false,
1428
                [true, true, true, false],
1429
                false
1430
            );
1431
        }
1432
1433
        return $html_messages;
1434
    }
1435
1436
    /**
1437
     * Displays messages of a group with nested view.
1438
     *
1439
     * @param $group_id
1440
     * @param $topic_id
1441
     * @param $is_member
1442
     * @param $messageId
1443
     *
1444
     * @return string
1445
     */
1446
    public static function display_message_for_group($group_id, $topic_id, $is_member, $messageId)
0 ignored issues
show
Unused Code introduced by
The parameter $is_member is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1446
    public static function display_message_for_group($group_id, $topic_id, /** @scrutinizer ignore-unused */ $is_member, $messageId)

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

Loading history...
Unused Code introduced by
The parameter $messageId is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1446
    public static function display_message_for_group($group_id, $topic_id, $is_member, /** @scrutinizer ignore-unused */ $messageId)

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

Loading history...
1447
    {
1448
        global $my_group_role;
1449
        $main_message = self::get_message_by_id($topic_id);
1450
        if (empty($main_message)) {
1451
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
1452
        }
1453
        $rows = self::get_messages_by_group_by_message($group_id, $topic_id);
1454
        $rows = self::calculate_children($rows, $topic_id);
1455
        $current_user_id = api_get_user_id();
1456
1457
        $items_per_page = 50;
1458
        $query_vars = ['id' => $group_id, 'topic_id' => $topic_id, 'topics_page_nr' => 0];
1459
1460
        // Main message
1461
        $links = '';
1462
        $main_content = '';
1463
        $html = '';
1464
        $items_page_nr = null;
1465
1466
        $user_sender_info = api_get_user_info($main_message['user_sender_id']);
1467
        $files_attachments = self::get_links_message_attachment_files($main_message['id']);
1468
        $name = $user_sender_info['complete_name'];
1469
1470
        $topic_page_nr = isset($_GET['topics_page_nr']) ? intval($_GET['topics_page_nr']) : null;
1471
1472
        $links .= '<div class="pull-right">';
1473
        $links .= '<div class="btn-group btn-group-sm">';
1474
1475
        if (($my_group_role == GROUP_USER_PERMISSION_ADMIN ||
1476
                $my_group_role == GROUP_USER_PERMISSION_MODERATOR) ||
1477
            $main_message['user_sender_id'] == $current_user_id
1478
        ) {
1479
            $urlEdit = api_get_path(WEB_CODE_PATH);
1480
            $urlEdit .= 'social/message_for_group_form.inc.php?';
1481
            $urlEdit .= http_build_query(
1482
                [
1483
                    'user_friend' => $current_user_id,
1484
                    'group_id' => $group_id,
1485
                    'message_id' => $main_message['id'],
1486
                    'action' => 'edit_message_group',
1487
                    'anchor_topic' => 'topic_'.$main_message['id'],
1488
                    'topics_page_nr' => $topic_page_nr,
1489
                    'items_page_nr' => $items_page_nr,
1490
                    'topic_id' => $main_message['id'],
1491
                ]
1492
            );
1493
1494
            $links .= Display::url(
1495
                Display::returnFontAwesomeIcon('pencil'),
1496
                $urlEdit,
1497
                [
1498
                    'class' => 'btn btn-default ajax',
1499
                    'title' => get_lang('Edit'),
1500
                    'data-title' => get_lang('Edit'),
1501
                    'data-size' => 'lg',
1502
                ]
1503
            );
1504
        }
1505
1506
        $urlReply = api_get_path(WEB_CODE_PATH);
1507
        $urlReply .= 'social/message_for_group_form.inc.php?';
1508
        $urlReply .= http_build_query(
1509
            [
1510
                'user_friend' => api_get_user_id(),
1511
                'group_id' => $group_id,
1512
                'message_id' => $main_message['id'],
1513
                'action' => 'reply_message_group',
1514
                'anchor_topic' => 'topic_'.$main_message['id'],
1515
                'topics_page_nr' => $topic_page_nr,
1516
                'topic_id' => $main_message['id'],
1517
            ]
1518
        );
1519
1520
        $links .= Display::url(
1521
            Display::returnFontAwesomeIcon('commenting'),
1522
            $urlReply,
1523
            [
1524
                'class' => 'btn btn-default ajax',
1525
                'title' => get_lang('Reply'),
1526
                'data-title' => get_lang('Reply'),
1527
                'data-size' => 'lg',
1528
            ]
1529
        );
1530
1531
        if (api_is_platform_admin()) {
1532
            $links .= Display::url(
1533
                Display::returnFontAwesomeIcon('trash'),
1534
                'group_topics.php?action=delete&id='.$group_id.'&topic_id='.$topic_id,
1535
                [
1536
                    'class' => 'btn btn-default',
1537
                ]
1538
            );
1539
        }
1540
1541
        $links .= '</div>';
1542
        $links .= '</div>';
1543
1544
        $title = '<h4>'.Security::remove_XSS($main_message['title'], STUDENT, true).$links.'</h4>';
1545
1546
        $userPicture = $user_sender_info['avatar'];
1547
        $main_content .= '<div class="row">';
1548
        $main_content .= '<div class="col-md-2">';
1549
        $main_content .= '<div class="avatar-author">';
1550
        $main_content .= '<img width="60px" src="'.$userPicture.'" alt="'.$name.'" class="img-responsive img-circle" title="'.$name.'" />';
1551
        $main_content .= '</div>';
1552
        $main_content .= '</div>';
1553
1554
        $date = '';
1555
        if ($main_message['send_date'] != $main_message['update_date']) {
1556
            if (!empty($main_message['update_date'])) {
1557
                $date = '<div class="date"> '.
1558
                    Display::returnFontAwesomeIcon('calendar').' '.get_lang('LastUpdate').' '.
1559
                    Display::dateToStringAgoAndLongDate($main_message['update_date']).
1560
                    '</div>';
1561
            }
1562
        } else {
1563
            $date = '<div class="date"> '.
1564
                Display::returnFontAwesomeIcon('calendar').' '.get_lang('Created').' '.
1565
                Display::dateToStringAgoAndLongDate($main_message['send_date']).
1566
                '</div>';
1567
        }
1568
        $attachment = '<div class="message-attach">'.(!empty($files_attachments) ? implode(
1569
                '<br />',
1570
                $files_attachments
1571
            ) : '').'</div>';
1572
        $main_content .= '<div class="col-md-10">';
1573
        $user_link = '<a href="'.api_get_path(
1574
                WEB_PATH
1575
            ).'main/social/profile.php?u='.$main_message['user_sender_id'].'">'.$name.'</a>';
1576
        $main_content .= '<div class="message-content"> ';
1577
        $main_content .= '<div class="username">'.$user_link.'</div>';
1578
        $main_content .= $date;
1579
        $main_content .= '<div class="message">'.$main_message['content'].$attachment.'</div></div>';
1580
        $main_content .= '</div>';
1581
        $main_content .= '</div>';
1582
1583
        $html .= Display::div(
1584
            Display::div(
1585
                $title.$main_content,
1586
                ['class' => 'message-topic']
1587
            ),
1588
            ['class' => 'sm-groups-message']
1589
        );
1590
1591
        $topic_id = $main_message['id'];
1592
1593
        if (is_array($rows) && count($rows) > 0) {
1594
            $topics = $rows;
1595
            $array_html_items = [];
1596
            foreach ($topics as $index => $topic) {
1597
                if (empty($topic['id'])) {
1598
                    continue;
1599
                }
1600
                $items_page_nr = isset($_GET['items_'.$topic['id'].'_page_nr']) ? intval($_GET['items_'.$topic['id'].'_page_nr']) : null;
1601
                $links = '';
1602
                $links .= '<div class="pull-right">';
1603
                $html_items = '';
1604
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1605
                $files_attachments = self::get_links_message_attachment_files($topic['id']);
1606
                $name = $user_sender_info['complete_name'];
1607
1608
                $links .= '<div class="btn-group btn-group-sm">';
1609
                if (($my_group_role == GROUP_USER_PERMISSION_ADMIN || $my_group_role == GROUP_USER_PERMISSION_MODERATOR) ||
1610
                    $topic['user_sender_id'] == $current_user_id
1611
                ) {
1612
                    $links .= '<a href="'.api_get_path(WEB_CODE_PATH).'social/message_for_group_form.inc.php?height=400&width=800&&user_friend='.$current_user_id.'&group_id='.$group_id.'&message_id='.$topic['id'].'&action=edit_message_group&anchor_topic=topic_'.$topic_id.'&topics_page_nr='.$topic_page_nr.'&items_page_nr='.$items_page_nr.'&topic_id='.$topic_id.'" class="ajax btn btn-default" data-size="lg" data-title="'.get_lang('Edit').'" title="'.get_lang('Edit').'">'.
1613
                        Display::returnFontAwesomeIcon('pencil').'</a>';
1614
                }
1615
                $links .= '<a href="'.api_get_path(WEB_CODE_PATH).'social/message_for_group_form.inc.php?height=400&width=800&&user_friend='.api_get_user_id().'&group_id='.$group_id.'&message_id='.$topic['id'].'&action=reply_message_group&anchor_topic=topic_'.$topic_id.'&topics_page_nr='.$topic_page_nr.'&items_page_nr='.$items_page_nr.'&topic_id='.$topic_id.'" class="ajax btn btn-default" data-size="lg" data-title="'.get_lang('Reply').'" title="'.get_lang('Reply').'">';
1616
                $links .= Display::returnFontAwesomeIcon('commenting').'</a>';
1617
                $links .= '</div>';
1618
                $links .= '</div>';
1619
1620
                $userPicture = $user_sender_info['avatar'];
1621
                $user_link = '<a href="'.api_get_path(WEB_PATH).'main/social/profile.php?u='.$topic['user_sender_id'].'">'.$name.'&nbsp</a>';
1622
                $html_items .= '<div class="row">';
1623
                $html_items .= '<div class="col-md-2">';
1624
                $html_items .= '<div class="avatar-author">';
1625
                $html_items .= '<img width="60px" src="'.$userPicture.'" alt="'.$name.'" class="img-responsive img-circle" title="'.$name.'" /></div>';
1626
                $html_items .= '</div>';
1627
1628
                $date = '';
1629
                if ($topic['send_date'] != $topic['update_date']) {
1630
                    if (!empty($topic['update_date'])) {
1631
                        $date = '<div class="date"> '.
1632
                            Display::returnFontAwesomeIcon('calendar').' '.
1633
                            get_lang('LastUpdate').' '.Display::dateToStringAgoAndLongDate($topic['update_date']).
1634
                        '</div>';
1635
                    }
1636
                } else {
1637
                    $date = '<div class="date"> '.
1638
                        Display::returnFontAwesomeIcon('calendar').
1639
                        get_lang('Created').' '.Display::dateToStringAgoAndLongDate($topic['send_date']).
1640
                    '</div>';
1641
                }
1642
                $attachment = '<div class="message-attach">'.(!empty($files_attachments) ? implode('<br />', $files_attachments) : '').'</div>';
1643
                $html_items .= '<div class="col-md-10">';
1644
                $html_items .= '<div class="message-content">';
1645
                $html_items .= $links;
1646
                $html_items .= '<div class="username">'.$user_link.'</div>';
1647
                $html_items .= $date;
1648
                $html_items .= '<div class="message">'.
1649
                    Security::remove_XSS($topic['content'], STUDENT, true).
1650
                    '</div>'.$attachment.'</div>';
1651
                $html_items .= '</div>';
1652
                $html_items .= '</div>';
1653
1654
                $base_padding = 20;
1655
1656
                if ($topic['indent_cnt'] == 0) {
1657
                    $indent = $base_padding;
1658
                } else {
1659
                    $indent = intval($topic['indent_cnt']) * $base_padding + $base_padding;
1660
                }
1661
1662
                $html_items = Display::div($html_items, ['class' => 'message-post', 'id' => 'msg_'.$topic['id']]);
1663
                $html_items = Display::div($html_items, ['class' => '', 'style' => 'margin-left:'.$indent.'px']);
1664
                $array_html_items[] = [$html_items];
1665
            }
1666
1667
            // grids for items with paginations
1668
            $options = ['hide_navigation' => false, 'per_page' => $items_per_page];
1669
            $visibility = [true, true, true, false];
1670
1671
            $style_class = [
1672
                'item' => ['class' => 'user-post'],
1673
                'main' => ['class' => 'user-list'],
1674
            ];
1675
            if (!empty($array_html_items)) {
1676
                $html .= Display::return_sortable_grid(
1677
                    'items_'.$topic['id'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $topic seems to be defined by a foreach iteration on line 1596. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1678
                    [],
1679
                    $array_html_items,
1680
                    $options,
1681
                    $query_vars,
1682
                    null,
1683
                    $visibility,
1684
                    false,
1685
                    $style_class
1686
                );
1687
            }
1688
        }
1689
1690
        return $html;
1691
    }
1692
1693
    /**
1694
     * Add children to messages by id is used for nested view messages.
1695
     *
1696
     * @param array $rows rows of messages
1697
     *
1698
     * @return array $first_seed new list adding the item children
1699
     */
1700
    public static function calculate_children($rows, $first_seed)
1701
    {
1702
        $rows_with_children = [];
1703
        foreach ($rows as $row) {
1704
            $rows_with_children[$row["id"]] = $row;
1705
            $rows_with_children[$row["parent_id"]]["children"][] = $row["id"];
1706
        }
1707
        $rows = $rows_with_children;
1708
        $sorted_rows = [0 => []];
1709
        self::message_recursive_sort($rows, $sorted_rows, $first_seed);
1710
        unset($sorted_rows[0]);
1711
1712
        return $sorted_rows;
1713
    }
1714
1715
    /**
1716
     * Sort recursively the messages, is used for for nested view messages.
1717
     *
1718
     * @param array  original rows of messages
1719
     * @param array  list recursive of messages
1720
     * @param int   seed for calculate the indent
1721
     * @param int   indent for nested view
1722
     */
1723
    public static function message_recursive_sort(
1724
        $rows,
1725
        &$messages,
1726
        $seed = 0,
1727
        $indent = 0
1728
    ) {
1729
        if ($seed > 0 && isset($rows[$seed]["id"])) {
1730
            $messages[$rows[$seed]["id"]] = $rows[$seed];
1731
            $messages[$rows[$seed]["id"]]["indent_cnt"] = $indent;
1732
            $indent++;
1733
        }
1734
1735
        if (isset($rows[$seed]["children"])) {
1736
            foreach ($rows[$seed]["children"] as $child) {
1737
                self::message_recursive_sort($rows, $messages, $child, $indent);
1738
            }
1739
        }
1740
    }
1741
1742
    /**
1743
     * Sort date by desc from a multi-dimensional array.
1744
     *
1745
     * @param array $array1 first array to compare
1746
     * @param array $array2 second array to compare
1747
     *
1748
     * @return bool
1749
     */
1750
    public function order_desc_date($array1, $array2)
1751
    {
1752
        return strcmp($array2['send_date'], $array1['send_date']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return strcmp($array2['s..., $array1['send_date']) returns the type integer which is incompatible with the documented return type boolean.
Loading history...
1753
    }
1754
1755
    /**
1756
     * Get array of links (download) for message attachment files.
1757
     *
1758
     * @param int    $messageId
1759
     * @param string $type      message list (inbox/outbox)
1760
     *
1761
     * @return array
1762
     */
1763
    public static function get_links_message_attachment_files($messageId, $type = '')
1764
    {
1765
        $table = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
1766
        $messageId = intval($messageId);
1767
1768
        // get file attachments by message id
1769
        $links_attach_file = [];
1770
        if (!empty($messageId)) {
1771
            $sql = "SELECT * FROM $table
1772
                    WHERE message_id = '$messageId'";
1773
1774
            $rs_file = Database::query($sql);
1775
            if (Database::num_rows($rs_file) > 0) {
1776
                $attach_icon = Display::return_icon('attachment.gif', '');
1777
                $archiveURL = api_get_path(WEB_CODE_PATH).'messages/download.php?type='.$type.'&file=';
1778
                while ($row_file = Database::fetch_array($rs_file)) {
1779
                    $archiveFile = $row_file['path'];
1780
                    $filename = $row_file['filename'];
1781
                    $filesize = format_file_size($row_file['size']);
1782
                    $filecomment = Security::remove_XSS($row_file['comment']);
1783
                    $filename = Security::remove_XSS($filename);
1784
                    $links_attach_file[] = $attach_icon.'&nbsp;<a href="'.$archiveURL.$archiveFile.'">'.$filename.'</a>
1785
                        &nbsp;('.$filesize.')'.(!empty($filecomment) ? '&nbsp;-&nbsp;<i>'.$filecomment.'</i>' : '');
1786
                }
1787
            }
1788
        }
1789
1790
        return $links_attach_file;
1791
    }
1792
1793
    /**
1794
     * Get message list by id.
1795
     *
1796
     * @param int $messageId
1797
     *
1798
     * @return array
1799
     */
1800
    public static function get_message_by_id($messageId)
1801
    {
1802
        $table = Database::get_main_table(TABLE_MESSAGE);
1803
        $messageId = intval($messageId);
1804
        $sql = "SELECT * FROM $table
1805
                WHERE 
1806
                    id = '$messageId' AND 
1807
                    msg_status <> '".MESSAGE_STATUS_DELETED."' ";
1808
        $res = Database::query($sql);
1809
        $item = [];
1810
        if (Database::num_rows($res) > 0) {
1811
            $item = Database::fetch_array($res, 'ASSOC');
1812
        }
1813
1814
        return $item;
1815
    }
1816
1817
    /**
1818
     * @return string
1819
     */
1820
    public static function generate_message_form()
1821
    {
1822
        $form = new FormValidator('send_message');
1823
        $form->addText(
1824
            'subject',
1825
            get_lang('Subject'),
1826
            false,
1827
            ['id' => 'subject_id']
1828
        );
1829
        $form->addTextarea(
1830
            'content',
1831
            get_lang('Message'),
1832
            ['id' => 'content_id', 'rows' => '5']
1833
        );
1834
1835
        return $form->returnForm();
1836
    }
1837
1838
    /**
1839
     * @param $id
1840
     * @param array $params
1841
     *
1842
     * @return string
1843
     */
1844
    public static function generate_invitation_form($id, $params = [])
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1844
    public static function generate_invitation_form(/** @scrutinizer ignore-unused */ $id, $params = [])

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

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1844
    public static function generate_invitation_form($id, /** @scrutinizer ignore-unused */ $params = [])

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

Loading history...
1845
    {
1846
        $form = new FormValidator('send_invitation');
1847
        $form->addTextarea(
1848
            'content',
1849
            get_lang('AddPersonalMessage'),
1850
            ['id' => 'content_invitation_id', 'rows' => 5]
1851
        );
1852
1853
        return $form->returnForm();
1854
    }
1855
1856
    //@todo this functions should be in the message class
1857
1858
    /**
1859
     * @param string $keyword
1860
     *
1861
     * @return string
1862
     */
1863
    public static function inbox_display($keyword = '')
1864
    {
1865
        $success = get_lang('SelectedMessagesDeleted');
1866
        $success_read = get_lang('SelectedMessagesRead');
1867
        $success_unread = get_lang('SelectedMessagesUnRead');
1868
        $html = '';
1869
1870
        Session::write('message_search_keyword', $keyword);
1871
1872
        if (isset($_REQUEST['action'])) {
1873
            switch ($_REQUEST['action']) {
1874
                case 'mark_as_unread':
1875
                    if (is_array($_POST['id'])) {
1876
                        foreach ($_POST['id'] as $index => $message_id) {
1877
                            self::update_message_status(
1878
                                api_get_user_id(),
1879
                                $message_id,
1880
                                MESSAGE_STATUS_UNREAD
1881
                            );
1882
                        }
1883
                    }
1884
                    $html .= Display::return_message(
1885
                        api_xml_http_response_encode($success_unread),
1886
                        'normal',
1887
                        false
1888
                    );
1889
                    break;
1890
                case 'mark_as_read':
1891
                    if (is_array($_POST['id'])) {
1892
                        foreach ($_POST['id'] as $index => $message_id) {
1893
                            self::update_message_status(
1894
                                api_get_user_id(),
1895
                                $message_id,
1896
                                MESSAGE_STATUS_NEW
1897
                            );
1898
                        }
1899
                    }
1900
                    $html .= Display::return_message(
1901
                        api_xml_http_response_encode($success_read),
1902
                        'normal',
1903
                        false
1904
                    );
1905
                    break;
1906
                case 'delete':
1907
                    foreach ($_POST['id'] as $index => $message_id) {
1908
                        self::delete_message_by_user_receiver(api_get_user_id(), $message_id);
1909
                    }
1910
                    $html .= Display::return_message(
1911
                        api_xml_http_response_encode($success),
1912
                        'normal',
1913
                        false
1914
                    );
1915
                    break;
1916
                case 'deleteone':
1917
                    self::delete_message_by_user_receiver(api_get_user_id(), $_GET['id']);
1918
                    $html .= Display::return_message(
1919
                        api_xml_http_response_encode($success),
1920
                        'confirmation',
1921
                        false
1922
                    );
1923
                    break;
1924
            }
1925
        }
1926
1927
        // display sortable table with messages of the current user
1928
        $table = new SortableTable(
1929
            'message_inbox',
1930
            ['MessageManager', 'getNumberOfMessages'],
1931
            ['MessageManager', 'get_message_data'],
1932
            2,
1933
            20,
1934
            'DESC'
1935
        );
1936
        $table->set_header(0, '', false, ['style' => 'width:15px;']);
1937
        $table->set_header(1, get_lang('Messages'), false);
1938
        $table->set_header(2, get_lang('Date'), true, ['style' => 'width:180px;']);
1939
        $table->set_header(3, get_lang('Modify'), false, ['style' => 'width:120px;']);
1940
1941
        if (isset($_REQUEST['f']) && $_REQUEST['f'] == 'social') {
1942
            $parameters['f'] = 'social';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$parameters was never initialized. Although not strictly required by PHP, it is generally a good practice to add $parameters = array(); before regardless.
Loading history...
1943
            $table->set_additional_parameters($parameters);
1944
        }
1945
        $table->set_form_actions(
1946
            [
1947
                'delete' => get_lang('DeleteSelectedMessages'),
1948
                'mark_as_unread' => get_lang('MailMarkSelectedAsUnread'),
1949
                'mark_as_read' => get_lang('MailMarkSelectedAsRead'),
1950
            ]
1951
        );
1952
        $html .= $table->return_table();
1953
1954
        Session::erase('message_search_keyword');
1955
1956
        return $html;
1957
    }
1958
1959
    /**
1960
     * @param string $keyword
1961
     *
1962
     * @return string
1963
     */
1964
    public static function outbox_display($keyword = '')
1965
    {
1966
        Session::write('message_sent_search_keyword', $keyword);
1967
        $success = get_lang('SelectedMessagesDeleted').'&nbsp</b><br />
1968
                    <a href="outbox.php">'.get_lang('BackToOutbox').'</a>';
1969
1970
        $html = '';
1971
        if (isset($_REQUEST['action'])) {
1972
            switch ($_REQUEST['action']) {
1973
                case 'delete':
1974
                    $number_of_selected_messages = count($_POST['id']);
1975
                    if ($number_of_selected_messages != 0) {
1976
                        foreach ($_POST['id'] as $index => $message_id) {
1977
                            self::delete_message_by_user_receiver(
1978
                                api_get_user_id(),
1979
                                $message_id
1980
                            );
1981
                        }
1982
                    }
1983
                    $html .= Display::return_message(api_xml_http_response_encode($success), 'normal', false);
1984
                    break;
1985
                case 'deleteone':
1986
                    self::delete_message_by_user_receiver(api_get_user_id(), $_GET['id']);
1987
                    $html .= Display::return_message(api_xml_http_response_encode($success), 'normal', false);
1988
                    $html .= '<br/>';
1989
                    break;
1990
            }
1991
        }
1992
1993
        // display sortable table with messages of the current user
1994
        $table = new SortableTable(
1995
            'message_outbox',
1996
            ['MessageManager', 'getNumberOfMessagesSent'],
1997
            ['MessageManager', 'get_message_data_sent'],
1998
            2,
1999
            20,
2000
            'DESC'
2001
        );
2002
2003
        $table->set_header(0, '', false, ['style' => 'width:15px;']);
2004
        $table->set_header(1, get_lang('Messages'), false);
2005
        $table->set_header(2, get_lang('Date'), true, ['style' => 'width:180px;']);
2006
        $table->set_header(3, get_lang('Modify'), false, ['style' => 'width:70px;']);
2007
2008
        $table->set_form_actions(['delete' => get_lang('DeleteSelectedMessages')]);
2009
        $html .= $table->return_table();
2010
2011
        Session::erase('message_sent_search_keyword');
2012
2013
        return $html;
2014
    }
2015
2016
    /**
2017
     * Get the count of the last received messages for a user.
2018
     *
2019
     * @param int $userId The user id
2020
     * @param int $lastId The id of the last received message
2021
     *
2022
     * @return int The count of new messages
2023
     */
2024
    public static function countMessagesFromLastReceivedMessage($userId, $lastId = 0)
2025
    {
2026
        $userId = intval($userId);
2027
        $lastId = intval($lastId);
2028
2029
        if (empty($userId)) {
2030
            return 0;
2031
        }
2032
2033
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2034
2035
        $conditions = [
2036
            'where' => [
2037
                'user_receiver_id = ?' => $userId,
2038
                'AND msg_status = ?' => MESSAGE_STATUS_UNREAD,
2039
                'AND id > ?' => $lastId,
2040
            ],
2041
        ];
2042
2043
        $result = Database::select('COUNT(1) AS qty', $messagesTable, $conditions);
2044
2045
        if (!empty($result)) {
2046
            $row = current($result);
2047
2048
            return $row['qty'];
2049
        }
2050
2051
        return 0;
2052
    }
2053
2054
    /**
2055
     * Get the data of the last received messages for a user.
2056
     *
2057
     * @param int $userId The user id
2058
     * @param int $lastId The id of the last received message
2059
     *
2060
     * @return array
2061
     */
2062
    public static function getMessagesFromLastReceivedMessage($userId, $lastId = 0)
2063
    {
2064
        $userId = intval($userId);
2065
        $lastId = intval($lastId);
2066
2067
        if (empty($userId)) {
2068
            return [];
2069
        }
2070
2071
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2072
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2073
2074
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname
2075
                FROM $messagesTable as m
2076
                INNER JOIN $userTable as u
2077
                ON m.user_sender_id = u.user_id
2078
                WHERE
2079
                    m.user_receiver_id = $userId AND
2080
                    m.msg_status = ".MESSAGE_STATUS_UNREAD."
2081
                    AND m.id > $lastId
2082
                ORDER BY m.send_date DESC";
2083
2084
        $result = Database::query($sql);
2085
2086
        $messages = [];
2087
        if ($result !== false) {
2088
            while ($row = Database::fetch_assoc($result)) {
2089
                $messages[] = $row;
2090
            }
2091
        }
2092
2093
        return $messages;
2094
    }
2095
2096
    /**
2097
     * Check whether a message has attachments.
2098
     *
2099
     * @param int $messageId The message id
2100
     *
2101
     * @return bool Whether the message has attachments return true. Otherwise return false
2102
     */
2103
    public static function hasAttachments($messageId)
2104
    {
2105
        $messageId = intval($messageId);
2106
2107
        if (empty($messageId)) {
2108
            return false;
2109
        }
2110
2111
        $messageAttachmentTable = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
2112
2113
        $conditions = [
2114
            'where' => [
2115
                'message_id = ?' => $messageId,
2116
            ],
2117
        ];
2118
2119
        $result = Database::select(
2120
            'COUNT(1) AS qty',
2121
            $messageAttachmentTable,
2122
            $conditions,
2123
            'first'
2124
        );
2125
2126
        if (!empty($result)) {
2127
            if ($result['qty'] > 0) {
2128
                return true;
2129
            }
2130
        }
2131
2132
        return false;
2133
    }
2134
2135
    /**
2136
     * @param string $url
2137
     *
2138
     * @return FormValidator
2139
     */
2140
    public static function getSearchForm($url)
2141
    {
2142
        $form = new FormValidator(
2143
            'search',
2144
            'post',
2145
            $url,
2146
            null,
2147
            [],
2148
            FormValidator::LAYOUT_INLINE
2149
        );
2150
2151
        $form->addElement(
2152
            'text',
2153
            'keyword',
2154
            false,
2155
            [
2156
                'aria-label' => get_lang('Search'),
2157
            ]
2158
        );
2159
        $form->addButtonSearch(get_lang('Search'));
2160
2161
        return $form;
2162
    }
2163
2164
    /**
2165
     * Send a notification to all admins when a new user is registered.
2166
     *
2167
     * @param User $user
2168
     */
2169
    public static function sendNotificationByRegisteredUser(User $user)
2170
    {
2171
        $tplMailBody = new Template(
2172
            null,
2173
            false,
2174
            false,
2175
            false,
2176
            false,
2177
            false,
2178
            false
2179
        );
2180
        $tplMailBody->assign('user', $user);
2181
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
2182
        $tplMailBody->assign(
2183
            'manageUrl',
2184
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$user->getId()
2185
        );
2186
2187
        $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin.tpl');
2188
2189
        $emailsubject = '['.get_lang('UserRegistered').'] '.$user->getUsername();
2190
        $emailbody = $tplMailBody->fetch($layoutContent);
2191
2192
        $admins = UserManager::get_all_administrators();
2193
2194
        foreach ($admins as $admin_info) {
2195
            self::send_message(
2196
                $admin_info['user_id'],
2197
                $emailsubject,
2198
                $emailbody,
2199
                [],
2200
                [],
2201
                null,
2202
                null,
2203
                null,
2204
                null,
2205
                $user->getId()
2206
            );
2207
        }
2208
    }
2209
2210
    /**
2211
     * Get the error log from failed mailing
2212
     * This assumes a complex setup where you have a cron script regularly copying the mail queue log
2213
     * into app/cache/mail/mailq.
2214
     * This can be done with a cron command like (check the location of your mail log file first):.
2215
     *
2216
     * @example 0,30 * * * * root cp /var/log/exim4/mainlog /var/www/chamilo/app/cache/mail/mailq
2217
     *
2218
     * @return array|bool
2219
     */
2220
    public static function failedSentMailErrors()
2221
    {
2222
        $base = api_get_path(SYS_ARCHIVE_PATH).'mail/';
2223
        $mailq = $base.'mailq';
2224
2225
        if (!file_exists($mailq) || !is_readable($mailq)) {
2226
            return false;
2227
        }
2228
2229
        $file = fopen($mailq, 'r');
2230
        $i = 1;
2231
        while (!feof($file)) {
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type false; however, parameter $handle of feof() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2231
        while (!feof(/** @scrutinizer ignore-type */ $file)) {
Loading history...
2232
            $line = fgets($file);
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type false; however, parameter $handle of fgets() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2232
            $line = fgets(/** @scrutinizer ignore-type */ $file);
Loading history...
2233
            //$line = trim($line);
2234
2235
            if (trim($line) == '') {
2236
                continue;
2237
            }
2238
2239
            //Get the mail code, something like 1WBumL-0002xg-FF
2240
            if (preg_match('/(.*)\s((.*)-(.*)-(.*))\s<(.*)$/', $line, $codeMatches)) {
2241
                $mail_queue[$i]['code'] = $codeMatches[2];
2242
            }
2243
2244
            $fullMail = $base.$mail_queue[$i]['code'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mail_queue does not seem to be defined for all execution paths leading up to this point.
Loading history...
2245
            $mailFile = fopen($fullMail, 'r');
2246
2247
            //Get the reason of mail fail
2248
            $iX = 1;
2249
2250
            while (!feof($mailFile)) {
2251
                $mailLine = fgets($mailFile);
2252
                //if ($iX == 4 && preg_match('/(.*):\s(.*)$/', $mailLine, $matches)) {
2253
                if ($iX == 2 &&
2254
                    preg_match('/(.*)(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s(.*)/', $mailLine, $detailsMatches)
2255
                ) {
2256
                    $mail_queue[$i]['reason'] = $detailsMatches[3];
2257
                }
2258
2259
                $iX++;
2260
            }
2261
2262
            fclose($mailFile);
0 ignored issues
show
Bug introduced by
It seems like $mailFile can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2262
            fclose(/** @scrutinizer ignore-type */ $mailFile);
Loading history...
2263
2264
            //Get the time of mail fail
2265
            if (preg_match('/^\s?(\d+)(\D+)\s+(.*)$/', $line, $timeMatches)) {
2266
                $mail_queue[$i]['time'] = $timeMatches[1].$timeMatches[2];
2267
            } elseif (preg_match('/^(\s+)((.*)@(.*))\s+(.*)$/', $line, $emailMatches)) {
2268
                $mail_queue[$i]['mail'] = $emailMatches[2];
2269
                $i++;
2270
            }
2271
        }
2272
2273
        fclose($file);
2274
2275
        return array_reverse($mail_queue);
2276
    }
2277
2278
    /**
2279
     * @param int $userId
2280
     *
2281
     * @return array
2282
     */
2283
    public static function getUsersThatHadConversationWithUser($userId)
2284
    {
2285
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2286
        $userId = (int) $userId;
2287
2288
        $sql = "SELECT DISTINCT
2289
                    user_sender_id
2290
                FROM $messagesTable
2291
                WHERE
2292
                    user_receiver_id = ".$userId;
2293
        $result = Database::query($sql);
2294
        $users = Database::store_result($result);
2295
        $userList = [];
2296
        foreach ($users as $userData) {
2297
            $userId = $userData['user_sender_id'];
2298
            if (empty($userId)) {
2299
                continue;
2300
            }
2301
            $userInfo = api_get_user_info($userId);
2302
            if ($userInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2303
                $userList[$userId] = $userInfo;
2304
            }
2305
        }
2306
2307
        return $userList;
2308
    }
2309
2310
    /**
2311
     * @param int $userId
2312
     * @param int $otherUserId
2313
     *
2314
     * @return array
2315
     */
2316
    public static function getAllMessagesBetweenStudents($userId, $otherUserId)
2317
    {
2318
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2319
        $userId = (int) $userId;
2320
        $otherUserId = (int) $otherUserId;
2321
2322
        if (empty($otherUserId) || empty($userId)) {
2323
            return [];
2324
        }
2325
2326
        $sql = "SELECT DISTINCT * 
2327
                FROM $messagesTable
2328
                WHERE
2329
                    (user_receiver_id = $userId AND user_sender_id = $otherUserId) OR
2330
                    (user_receiver_id = $otherUserId AND user_sender_id = $userId)
2331
                ORDER BY send_date DESC
2332
            ";
2333
        $result = Database::query($sql);
2334
        $messages = Database::store_result($result);
2335
        $list = [];
2336
        foreach ($messages as $message) {
2337
            $list[] = $message;
2338
        }
2339
2340
        return $list;
2341
    }
2342
2343
    /**
2344
     * @param string $subject
2345
     * @param string $message
2346
     * @param array  $courseInfo
2347
     * @param int    $sessionId
2348
     *
2349
     * @return bool
2350
     */
2351
    public static function sendMessageToAllUsersInCourse($subject, $message, $courseInfo, $sessionId = 0)
2352
    {
2353
        if (empty($courseInfo)) {
2354
            return false;
2355
        }
2356
        $senderId = api_get_user_id();
2357
        if (empty($senderId)) {
2358
            return false;
2359
        }
2360
        if (empty($sessionId)) {
2361
            // Course students and teachers
2362
            $users = CourseManager::get_user_list_from_course_code($courseInfo['code']);
2363
        } else {
2364
            // Course-session students and course session coaches
2365
            $users = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
2366
        }
2367
2368
        if (empty($users)) {
2369
            return false;
2370
        }
2371
2372
        foreach ($users as $userInfo) {
2373
            self::send_message_simple(
2374
                $userInfo['user_id'],
2375
                $subject,
2376
                $message,
2377
                $senderId,
2378
                false,
2379
                false,
2380
                [],
2381
                false
2382
            );
2383
        }
2384
    }
2385
2386
    /**
2387
     * Execute the SQL necessary to know the number of messages in the database.
2388
     *
2389
     * @param int $userId The user for which we need the unread messages count
2390
     *
2391
     * @return int The number of unread messages in the database for the given user
2392
     */
2393
    private static function getCountNewMessagesFromDB($userId)
2394
    {
2395
        if (empty($userId)) {
2396
            return 0;
2397
        }
2398
        $table = Database::get_main_table(TABLE_MESSAGE);
2399
        $sql = "SELECT COUNT(id) as count 
2400
                FROM $table
2401
                WHERE
2402
                    user_receiver_id=".api_get_user_id()." AND
2403
                    msg_status = ".MESSAGE_STATUS_UNREAD;
2404
        $result = Database::query($sql);
2405
        $row = Database::fetch_assoc($result);
2406
2407
        return $row['count'];
2408
    }
2409
}
2410