· 9 years ago · Feb 16, 2017, 11:10 AM
1<?php
2/*
3 * @package AJAX_Chat
4 * @author Sebastian Tschan
5 * @copyright (c) Sebastian Tschan
6 * @license Modified MIT License
7 * @link https://blueimp.net/ajax/
8 */
9
10// Ajax Chat backend logic:
11class AJAXChat {
12
13 var $db;
14 var $_config;
15 var $_requestVars;
16 var $_infoMessages;
17 var $_channels;
18 var $_allChannels;
19 var $_view;
20 var $_lang;
21 var $_invitations;
22 var $_customVars;
23 var $_sessionNew;
24 var $_onlineUsersData;
25 var $_bannedUsersData;
26
27 function __construct() {
28 $this->initialize();
29 }
30
31 function initialize() {
32 // Initialize configuration settings:
33 $this->initConfig();
34
35 // Initialize the DataBase connection:
36 $this->initDataBaseConnection();
37
38 // Initialize request variables:
39 $this->initRequestVars();
40
41 // Initialize the chat session:
42 $this->initSession();
43
44 // Handle the browser request and send the response content:
45 $this->handleRequest();
46 }
47
48 function initConfig() {
49 $config = null;
50 if (!include(AJAX_CHAT_PATH.'lib/config.php')) {
51 echo('<strong>Error:</strong> Could not find a config.php file in "'.AJAX_CHAT_PATH.'"lib/". Check to make sure the file exists.');
52 die();
53 }
54 $this->_config = &$config;
55
56 // Initialize custom configuration settings:
57 $this->initCustomConfig();
58 }
59
60 function initRequestVars() {
61 $this->_requestVars = array();
62 $this->_requestVars['ajax'] = isset($_REQUEST['ajax']) ? true : false;
63 $this->_requestVars['userID'] = isset($_REQUEST['userID']) ? (int)$_REQUEST['userID'] : null;
64 $this->_requestVars['userName'] = isset($_REQUEST['userName']) ? $_REQUEST['userName'] : null;
65 $this->_requestVars['channelID'] = isset($_REQUEST['channelID']) ? (int)$_REQUEST['channelID'] : null;
66 $this->_requestVars['channelName'] = isset($_REQUEST['channelName']) ? $_REQUEST['channelName'] : null;
67 $this->_requestVars['text'] = isset($_POST['text']) ? $_POST['text'] : null;
68 $this->_requestVars['lastID'] = isset($_REQUEST['lastID']) ? (int)$_REQUEST['lastID'] : 0;
69 $this->_requestVars['login'] = isset($_REQUEST['login']) ? true : false;
70 $this->_requestVars['logout'] = isset($_REQUEST['logout']) ? true : false;
71 $this->_requestVars['password'] = isset($_REQUEST['password']) ? $_REQUEST['password'] : null;
72 $this->_requestVars['view'] = isset($_REQUEST['view']) ? $_REQUEST['view'] : null;
73 $this->_requestVars['year'] = isset($_REQUEST['year']) ? (int)$_REQUEST['year'] : null;
74 $this->_requestVars['month'] = isset($_REQUEST['month']) ? (int)$_REQUEST['month'] : null;
75 $this->_requestVars['day'] = isset($_REQUEST['day']) ? (int)$_REQUEST['day'] : null;
76 $this->_requestVars['hour'] = isset($_REQUEST['hour']) ? (int)$_REQUEST['hour'] : null;
77 $this->_requestVars['search'] = isset($_REQUEST['search']) ? $_REQUEST['search'] : null;
78 $this->_requestVars['shoutbox'] = isset($_REQUEST['shoutbox']) ? true : false;
79 $this->_requestVars['getInfos'] = isset($_REQUEST['getInfos']) ? $_REQUEST['getInfos'] : null;
80 $this->_requestVars['lang'] = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : null;
81 $this->_requestVars['delete'] = isset($_REQUEST['delete']) ? (int)$_REQUEST['delete'] : null;
82
83 // Initialize custom request variables:
84 $this->initCustomRequestVars();
85
86 // Remove slashes which have been added to user input strings if magic_quotes_gpc is On:
87 if(get_magic_quotes_gpc()) {
88 // It is safe to remove the slashes as we escape user data ourself
89 array_walk(
90 $this->_requestVars,
91 create_function(
92 '&$value, $key',
93 'if(is_string($value)) $value = stripslashes($value);'
94 )
95 );
96 }
97 }
98
99 function initDataBaseConnection() {
100 // Create a new database object:
101 $this->db = new AJAXChatDataBase(
102 $this->_config['dbConnection']
103 );
104 // Use a new database connection if no existing is given:
105 if(!$this->_config['dbConnection']['link']) {
106 // Connect to the database server:
107 $this->db->connect($this->_config['dbConnection']);
108 if($this->db->error()) {
109 echo $this->db->getError();
110 die();
111 }
112 // Select the database:
113 $this->db->select($this->_config['dbConnection']['name']);
114 if($this->db->error()) {
115 echo $this->db->getError();
116 die();
117 }
118 }
119 // Unset the dbConnection array for safety purposes:
120 unset($this->_config['dbConnection']);
121 }
122
123 function getDataBaseTable($table) {
124 return ($this->db->getName() ? '`'.$this->db->getName().'`.'.$this->getConfig('dbTableNames',$table) : $this->getConfig('dbTableNames',$table));
125 }
126
127 function initSession() {
128 // Start the PHP session (if not already started):
129 $this->startSession();
130
131 if($this->isLoggedIn()) {
132 // Logout if we receive a logout request, the chat has been closed or the userID could not be revalidated:
133 if($this->getRequestVar('logout') || !$this->isChatOpen() || !$this->revalidateUserID()) {
134 $this->logout();
135 return;
136 }
137 // Logout if the Session IP is not the same when logged in and ipCheck is enabled:
138 if($this->getConfig('ipCheck') && ($this->getSessionIP() === null || $this->getSessionIP() != $_SERVER['REMOTE_ADDR'])) {
139 $this->logout('IP');
140 return;
141 }
142 } else if(
143 // Login if auto-login enabled or a login, userName or shoutbox parameter is given:
144 $this->getConfig('forceAutoLogin') ||
145 $this->getRequestVar('login') ||
146 $this->getRequestVar('userName') ||
147 $this->getRequestVar('shoutbox')
148 ) {
149 $this->login();
150 }
151
152 // Initialize the view:
153 $this->initView();
154
155 if($this->getView() == 'chat') {
156 $this->initChatViewSession();
157 } else if($this->getView() == 'logs') {
158 $this->initLogsViewSession();
159 }
160
161 if(!$this->getRequestVar('ajax') && !headers_sent()) {
162 // Set style cookie:
163 $this->setStyle();
164 // Set langCode cookie:
165 $this->setLangCodeCookie();
166 }
167
168 $this->initCustomSession();
169 }
170
171 function initLogsViewSession() {
172 if($this->getConfig('socketServerEnabled')) {
173 if(!$this->getSessionVar('logsViewSocketAuthenticated')) {
174 $this->updateLogsViewSocketAuthentication();
175 $this->setSessionVar('logsViewSocketAuthenticated', true);
176 }
177 }
178 }
179
180 function updateLogsViewSocketAuthentication() {
181 if($this->getUserRole() != AJAX_CHAT_ADMIN) {
182 $channels = array();
183 foreach($this->getChannels() as $channel) {
184 if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) {
185 continue;
186 }
187 array_push($channels, $channel);
188 }
189 array_push($channels, $this->getPrivateMessageID());
190 array_push($channels, $this->getPrivateChannelID());
191 } else {
192 // The channelID "ALL" authenticates for all channels:
193 $channels = array('ALL');
194 }
195 $this->updateSocketAuthentication(
196 $this->getUserID(),
197 $this->getSocketRegistrationID(),
198 $channels
199 );
200 }
201
202 function initChatViewSession() {
203 // If channel is not null we are logged in to the chat view:
204 if($this->getChannel() !== null) {
205 // Check if the current user has been logged out due to inactivity:
206 if(!$this->isUserOnline()) {
207 $this->logout();
208 return;
209 }
210 if($this->getRequestVar('ajax')) {
211 $this->initChannel();
212 $this->updateOnlineStatus();
213 $this->checkAndRemoveInactive();
214 }
215 } else {
216 if($this->getRequestVar('ajax')) {
217 // Set channel, insert login messages and add to online list on first ajax request in chat view:
218 $this->chatViewLogin();
219 }
220 }
221 }
222
223 function isChatOpen() {
224 if($this->getUserRole() == AJAX_CHAT_ADMIN)
225 return true;
226 if($this->getConfig('chatClosed'))
227 return false;
228 $time = time();
229 if($this->getConfig('timeZoneOffset') !== null) {
230 // Subtract the server timezone offset and add the config timezone offset:
231 $time -= date('Z', $time);
232 $time += $this->getConfig('timeZoneOffset');
233 }
234 // Check the opening hours:
235 if($this->getConfig('openingHour') < $this->getConfig('closingHour'))
236 {
237 if(($this->getConfig('openingHour') > date('G', $time)) || ($this->getConfig('closingHour') <= date('G', $time)))
238 return false;
239 }
240 else
241 {
242 if(($this->getConfig('openingHour') > date('G', $time)) && ($this->getConfig('closingHour') <= date('G', $time)))
243 return false;
244 }
245 // Check the opening weekdays:
246 if(!in_array(date('w', $time), $this->getConfig('openingWeekDays')))
247 return false;
248 return true;
249 }
250
251 function handleRequest() {
252 if($this->getRequestVar('ajax')) {
253 if($this->isLoggedIn()) {
254 // Parse info requests (for current userName, etc.):
255 $this->parseInfoRequests();
256
257 // Parse command requests (e.g. message deletion):
258 $this->parseCommandRequests();
259
260 // Parse message requests:
261 $this->initMessageHandling();
262 }
263 // Send chat messages and online user list in XML format:
264 $this->sendXMLMessages();
265 } else {
266 // Display XHTML content for non-ajax requests:
267 $this->sendXHTMLContent();
268 }
269 }
270
271 function parseCommandRequests() {
272 if($this->getRequestVar('delete') !== null) {
273 $this->deleteMessage($this->getRequestVar('delete'));
274 }
275 }
276
277 function parseInfoRequests() {
278 if($this->getRequestVar('getInfos')) {
279 $infoRequests = explode(',', $this->getRequestVar('getInfos'));
280 foreach($infoRequests as $infoRequest) {
281 $this->parseInfoRequest($infoRequest);
282 }
283 }
284 }
285
286 function parseInfoRequest($infoRequest) {
287 switch($infoRequest) {
288 case 'userID':
289 $this->addInfoMessage($this->getUserID(), 'userID');
290 break;
291 case 'userName':
292 $this->addInfoMessage($this->getUserName(), 'userName');
293 break;
294 case 'userRole':
295 $this->addInfoMessage($this->getUserRole(), 'userRole');
296 break;
297 case 'channelID':
298 $this->addInfoMessage($this->getChannel(), 'channelID');
299 break;
300 case 'channelName':
301 $this->addInfoMessage($this->getChannelName(), 'channelName');
302 break;
303 case 'socketRegistrationID':
304 $this->addInfoMessage($this->getSocketRegistrationID(), 'socketRegistrationID');
305 break;
306 default:
307 $this->parseCustomInfoRequest($infoRequest);
308 }
309 }
310
311 function sendXHTMLContent() {
312 $httpHeader = new AJAXChatHTTPHeader($this->getConfig('contentEncoding'), $this->getConfig('contentType'));
313
314 $template = new AJAXChatTemplate($this, $this->getTemplateFileName(), $httpHeader->getContentType());
315
316 // Send HTTP header:
317 $httpHeader->send();
318
319 // Send parsed template content:
320 echo $template->getParsedContent();
321 }
322
323 function getTemplateFileName() {
324 switch($this->getView()) {
325 case 'chat':
326 return AJAX_CHAT_PATH.'lib/template/loggedIn.html';
327 case 'logs':
328 return AJAX_CHAT_PATH.'lib/template/logs.html';
329 default:
330 return AJAX_CHAT_PATH.'lib/template/loggedOut.html';
331 }
332 }
333
334 function initView() {
335 $this->_view = null;
336 // "chat" is the default view:
337 $view = ($this->getRequestVar('view') === null) ? 'chat' : $this->getRequestVar('view');
338 if($this->hasAccessTo($view)) {
339 $this->_view = $view;
340 }
341 }
342
343 function getView() {
344 return $this->_view;
345 }
346
347 function hasAccessTo($view) {
348 switch($view) {
349 case 'chat':
350 case 'teaser':
351 if($this->isLoggedIn()) {
352 return true;
353 }
354 return false;
355 case 'logs':
356 if($this->isLoggedIn() && ($this->getUserRole() == AJAX_CHAT_ADMIN ||
357 ($this->getConfig('logsUserAccess') &&
358 ($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_USER))
359 )) {
360 return true;
361 }
362 return false;
363 default:
364 return false;
365 }
366 }
367
368 function login() {
369 // Retrieve valid login user data (from request variables or session data):
370 $userData = $this->getValidLoginUserData();
371
372 if(!$userData) {
373 $this->addInfoMessage('errorInvalidUser');
374 return false;
375 }
376
377 // If the chat is closed, only the admin may login:
378 if(!$this->isChatOpen() && $userData['userRole'] != AJAX_CHAT_ADMIN) {
379 $this->addInfoMessage('errorChatClosed');
380 return false;
381 }
382
383 if(!$this->getConfig('allowGuestLogins') && $userData['userRole'] == AJAX_CHAT_GUEST) {
384 return false;
385 }
386
387 // Check if userID or userName are already listed online:
388 if($this->isUserOnline($userData['userID']) || $this->isUserNameInUse($userData['userName'])) {
389 if($userData['userRole'] == AJAX_CHAT_USER || $userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) {
390 // Set the registered user inactive and remove the inactive users so the user can be logged in again:
391 $this->setInactive($userData['userID'], $userData['userName']);
392 $this->removeInactive();
393 } else {
394 $this->addInfoMessage('errorUserInUse');
395 return false;
396 }
397 }
398
399 // Check if user is banned:
400 if($userData['userRole'] != AJAX_CHAT_ADMIN && $this->isUserBanned($userData['userName'], $userData['userID'], $_SERVER['REMOTE_ADDR'])) {
401 $this->addInfoMessage('errorBanned');
402 return false;
403 }
404
405 // Check if the max number of users is logged in (not affecting moderators or admins):
406 if(!($userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) && $this->isMaxUsersLoggedIn()) {
407 $this->addInfoMessage('errorMaxUsersLoggedIn');
408 return false;
409 }
410
411 // Use a new session id (if session has been started by the chat):
412 $this->regenerateSessionID();
413
414 // Log in:
415 $this->setUserID($userData['userID']);
416 $this->setUserName($userData['userName']);
417 $this->setLoginUserName($userData['userName']);
418 $this->setUserRole($userData['userRole']);
419 $this->setLoggedIn(true);
420 $this->setLoginTimeStamp(time());
421
422 // IP Security check variable:
423 $this->setSessionIP($_SERVER['REMOTE_ADDR']);
424
425 // The client authenticates to the socket server using a socketRegistrationID:
426 if($this->getConfig('socketServerEnabled')) {
427 $this->setSocketRegistrationID(
428 md5(uniqid(rand(), true))
429 );
430 }
431
432 // Add userID, userName and userRole to info messages:
433 $this->addInfoMessage($this->getUserID(), 'userID');
434 $this->addInfoMessage($this->getUserName(), 'userName');
435 $this->addInfoMessage($this->getUserRole(), 'userRole');
436
437 // Purge logs:
438 if($this->getConfig('logsPurgeLogs')) {
439 $this->purgeLogs();
440 }
441
442 return true;
443 }
444
445 function chatViewLogin() {
446 $this->setChannel($this->getValidRequestChannelID());
447 $this->addToOnlineList();
448
449 // Add channelID and channelName to info messages:
450 $this->addInfoMessage($this->getChannel(), 'channelID');
451 $this->addInfoMessage($this->getChannelName(), 'channelName');
452
453 // Login message:
454 $text = '/login '.$this->getUserName();
455 $this->insertChatBotMessage(
456 $this->getChannel(),
457 $text,
458 null,
459 1
460 );
461 }
462
463 function getValidRequestChannelID() {
464 $channelID = $this->getRequestVar('channelID');
465 $channelName = $this->getRequestVar('channelName');
466 // Check the given channelID, or get channelID from channelName:
467 if($channelID === null) {
468 if($channelName !== null) {
469 $channelID = $this->getChannelIDFromChannelName($channelName);
470 // channelName might need encoding conversion:
471 if($channelID === null) {
472 $channelID = $this->getChannelIDFromChannelName(
473 $this->trimChannelName($channelName, $this->getConfig('contentEncoding'))
474 );
475 }
476 }
477 }
478 // Validate the resulting channelID:
479 if(!$this->validateChannel($channelID)) {
480 if($this->getChannel() !== null) {
481 return $this->getChannel();
482 }
483 return $this->getConfig('defaultChannelID');
484 }
485 return $channelID;
486 }
487
488 function initChannel() {
489 $channelID = $this->getRequestVar('channelID');
490 $channelName = $this->getRequestVar('channelName');
491 if($channelID !== null) {
492 $this->switchChannel($this->getChannelNameFromChannelID($channelID));
493 } else if($channelName !== null) {
494 if($this->getChannelIDFromChannelName($channelName) === null) {
495 // channelName might need encoding conversion:
496 $channelName = $this->trimChannelName($channelName, $this->getConfig('contentEncoding'));
497 }
498 $this->switchChannel($channelName);
499 }
500 }
501
502 function logout($type=null) {
503 // Update the socket server authentication for the user:
504 if($this->getConfig('socketServerEnabled')) {
505 $this->updateSocketAuthentication($this->getUserID());
506 }
507 if($this->isUserOnline()) {
508 $this->chatViewLogout($type);
509 }
510 $this->setLoggedIn(false);
511 $this->destroySession();
512
513 // Re-initialize the view:
514 $this->initView();
515 }
516
517 function chatViewLogout($type) {
518 $this->removeFromOnlineList();
519 if($type !== null) {
520 $type = ' '.$type;
521 }
522 // Logout message
523 $text = '/logout '.$this->getUserName().$type;
524 $this->insertChatBotMessage(
525 $this->getChannel(),
526 $text,
527 null,
528 1
529 );
530 }
531
532 function switchChannel($channelName) {
533 $channelID = $this->getChannelIDFromChannelName($channelName);
534
535 if($channelID !== null && $this->getChannel() == $channelID) {
536 // User is already in the given channel, return:
537 return;
538 }
539
540 // Check if we have a valid channel:
541 if(!$this->validateChannel($channelID)) {
542 // Invalid channel:
543 $text = '/error InvalidChannelName '.$channelName;
544 $this->insertChatBotMessage(
545 $this->getPrivateMessageID(),
546 $text
547 );
548 return;
549 }
550
551 $oldChannel = $this->getChannel();
552
553 $this->setChannel($channelID);
554 $this->updateOnlineList();
555
556 // Channel leave message
557 $text = '/channelLeave '.$this->getUserName();
558 $this->insertChatBotMessage(
559 $oldChannel,
560 $text,
561 null,
562 1
563 );
564
565 // Channel enter message
566 $text = '/channelEnter '.$this->getUserName();
567 $this->insertChatBotMessage(
568 $this->getChannel(),
569 $text,
570 null,
571 1
572 );
573
574 $this->addInfoMessage($channelName, 'channelSwitch');
575 $this->addInfoMessage($channelID, 'channelID');
576 $this->_requestVars['lastID'] = 0;
577 }
578
579 function addToOnlineList() {
580 $sql = 'INSERT INTO '.$this->getDataBaseTable('online').'(
581 userID,
582 userName,
583 userRole,
584 channel,
585 dateTime,
586 ip
587 )
588 VALUES (
589 '.$this->db->makeSafe($this->getUserID()).',
590 '.$this->db->makeSafe($this->getUserName()).',
591 '.$this->db->makeSafe($this->getUserRole()).',
592 '.$this->db->makeSafe($this->getChannel()).',
593 NOW(),
594 '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).'
595 );';
596
597 // Create a new SQL query:
598 $result = $this->db->sqlQuery($sql);
599
600 // Stop if an error occurs:
601 if($result->error()) {
602 echo $result->getError();
603 die();
604 }
605
606 $this->resetOnlineUsersData();
607 }
608
609 function removeFromOnlineList() {
610 $sql = 'DELETE FROM
611 '.$this->getDataBaseTable('online').'
612 WHERE
613 userID = '.$this->db->makeSafe($this->getUserID()).';';
614
615 // Create a new SQL query:
616 $result = $this->db->sqlQuery($sql);
617
618 // Stop if an error occurs:
619 if($result->error()) {
620 echo $result->getError();
621 die();
622 }
623
624 $this->removeUserFromOnlineUsersData();
625 }
626
627 function updateOnlineList() {
628 $sql = 'UPDATE
629 '.$this->getDataBaseTable('online').'
630 SET
631 userName = '.$this->db->makeSafe($this->getUserName()).',
632 channel = '.$this->db->makeSafe($this->getChannel()).',
633 dateTime = NOW(),
634 ip = '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).'
635 WHERE
636 userID = '.$this->db->makeSafe($this->getUserID()).';';
637
638 // Create a new SQL query:
639 $result = $this->db->sqlQuery($sql);
640
641 // Stop if an error occurs:
642 if($result->error()) {
643 echo $result->getError();
644 die();
645 }
646
647 $this->resetOnlineUsersData();
648 }
649
650 function initMessageHandling() {
651 // Don't handle messages if we are not in chat view:
652 if($this->getView() != 'chat') {
653 return;
654 }
655
656 // Check if we have been uninvited from a private or restricted channel:
657 if(!$this->validateChannel($this->getChannel())) {
658 // Switch to the default channel:
659 $this->switchChannel($this->getChannelNameFromChannelID($this->getConfig('defaultChannelID')));
660 return;
661 }
662
663 if($this->getRequestVar('text') !== null) {
664 $this->insertMessage($this->getRequestVar('text'));
665 }
666 }
667
668 function insertParsedMessage($text) {
669
670 // If a queryUserName is set, sent all messages as private messages to this userName:
671 if($this->getQueryUserName() !== null && strpos($text, '/') !== 0) {
672 $text = '/msg '.$this->getQueryUserName().' '.$text;
673 }
674
675 // Parse IRC-style commands:
676 if(strpos($text, '/') === 0) {
677 $textParts = explode(' ', $text);
678
679 switch($textParts[0]) {
680
681 // Channel switch:
682 case '/join':
683 $this->insertParsedMessageJoin($textParts);
684 break;
685
686 // Logout:
687 case '/quit':
688 $this->logout();
689 break;
690
691 // Private message:
692 case '/msg':
693 case '/describe':
694 $this->insertParsedMessagePrivMsg($textParts);
695 break;
696
697 // Invitation:
698 case '/invite':
699 $this->insertParsedMessageInvite($textParts);
700 break;
701
702 // Uninvitation:
703 case '/uninvite':
704 $this->insertParsedMessageUninvite($textParts);
705 break;
706
707 // Private messaging:
708 case '/query':
709 $this->insertParsedMessageQuery($textParts);
710 break;
711
712 // Kicking offending users from the chat:
713 case '/kick':
714 $this->insertParsedMessageKick($textParts);
715 break;
716
717 // Listing banned users:
718 case '/bans':
719 $this->insertParsedMessageBans($textParts);
720 break;
721
722 // Unban user (remove from ban list):
723 case '/unban':
724 $this->insertParsedMessageUnban($textParts);
725 break;
726
727 // Describing actions:
728 case '/me':
729 case '/action':
730 $this->insertParsedMessageAction($textParts);
731 break;
732
733
734 // Listing online Users:
735 case '/who':
736 $this->insertParsedMessageWho($textParts);
737 break;
738
739 // Listing available channels:
740 case '/list':
741 $this->insertParsedMessageList($textParts);
742 break;
743
744 // Retrieving the channel of a User:
745 case '/whereis':
746 $this->insertParsedMessageWhereis($textParts);
747 break;
748
749 // Listing information about a User:
750 case '/whois':
751 $this->insertParsedMessageWhois($textParts);
752 break;
753
754 // Rolling dice:
755 case '/roll':
756 $this->insertParsedMessageRoll($textParts);
757 break;
758
759 // Switching userName:
760 case '/nick':
761 $this->insertParsedMessageNick($textParts);
762 break;
763
764 // Custom or unknown command:
765 default:
766 if(!$this->parseCustomCommands($text, $textParts)) {
767 $this->insertChatBotMessage(
768 $this->getPrivateMessageID(),
769 '/error UnknownCommand '.$textParts[0]
770 );
771 }
772 }
773
774 } else {
775 // No command found, just insert the plain message:
776 $this->insertCustomMessage(
777 $this->getUserID(),
778 $this->getUserName(),
779 $this->getUserRole(),
780 $this->getChannel(),
781 $text
782 );
783 }
784 }
785
786 function insertParsedMessageJoin($textParts) {
787 if(count($textParts) == 1) {
788 // join with no arguments is the own private channel, if allowed:
789 if($this->isAllowedToCreatePrivateChannel()) {
790 // Private channels are identified by square brackets:
791 $this->switchChannel($this->getChannelNameFromChannelID($this->getPrivateChannelID()));
792 } else {
793 $this->insertChatBotMessage(
794 $this->getPrivateMessageID(),
795 '/error MissingChannelName'
796 );
797 }
798 } else {
799 $this->switchChannel($textParts[1]);
800 }
801 }
802
803 function insertParsedMessagePrivMsg($textParts) {
804 if($this->isAllowedToSendPrivateMessage()) {
805 if(count($textParts) < 3) {
806 if(count($textParts) == 2) {
807 $this->insertChatBotMessage(
808 $this->getPrivateMessageID(),
809 '/error MissingText'
810 );
811 } else {
812 $this->insertChatBotMessage(
813 $this->getPrivateMessageID(),
814 '/error MissingUserName'
815 );
816 }
817 } else {
818 // Get UserID from UserName:
819 $toUserID = $this->getIDFromName($textParts[1]);
820 if($toUserID === null) {
821 if($this->getQueryUserName() !== null) {
822 // Close the current query:
823 $this->insertMessage('/query');
824 } else {
825 $this->insertChatBotMessage(
826 $this->getPrivateMessageID(),
827 '/error UserNameNotFound '.$textParts[1]
828 );
829 }
830 } else {
831 // Insert /privaction command if /describe is used:
832 $command = ($textParts[0] == '/describe') ? '/privaction' : '/privmsg';
833 // Copy of private message to current User:
834 $this->insertCustomMessage(
835 $this->getUserID(),
836 $this->getUserName(),
837 $this->getUserRole(),
838 $this->getPrivateMessageID(),
839 $command.'to '.$textParts[1].' '.implode(' ', array_slice($textParts, 2))
840 );
841 // Private message to requested User:
842 $this->insertCustomMessage(
843 $this->getUserID(),
844 $this->getUserName(),
845 $this->getUserRole(),
846 $this->getPrivateMessageID($toUserID),
847 $command.' '.implode(' ', array_slice($textParts, 2))
848 );
849 }
850 }
851 } else {
852 $this->insertChatBotMessage(
853 $this->getPrivateMessageID(),
854 '/error PrivateMessageNotAllowed'
855 );
856 }
857 }
858
859 function insertParsedMessageInvite($textParts) {
860 if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) {
861 if(count($textParts) == 1) {
862 $this->insertChatBotMessage(
863 $this->getPrivateMessageID(),
864 '/error MissingUserName'
865 );
866 } else {
867 $toUserID = $this->getIDFromName($textParts[1]);
868 if($toUserID === null) {
869 $this->insertChatBotMessage(
870 $this->getPrivateMessageID(),
871 '/error UserNameNotFound '.$textParts[1]
872 );
873 } else {
874 // Add the invitation to the database:
875 $this->addInvitation($toUserID);
876 $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel());
877 // Copy of invitation to current User:
878 $this->insertChatBotMessage(
879 $this->getPrivateMessageID(),
880 '/inviteto '.$textParts[1].' '.$invitationChannelName
881 );
882 // Invitation to requested User:
883 $this->insertChatBotMessage(
884 $this->getPrivateMessageID($toUserID),
885 '/invite '.$this->getUserName().' '.$invitationChannelName
886 );
887 }
888 }
889 } else {
890 $this->insertChatBotMessage(
891 $this->getPrivateMessageID(),
892 '/error InviteNotAllowed'
893 );
894 }
895 }
896
897 function insertParsedMessageUninvite($textParts) {
898 if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) {
899 if(count($textParts) == 1) {
900 $this->insertChatBotMessage(
901 $this->getPrivateMessageID(),
902 '/error MissingUserName'
903 );
904 } else {
905 $toUserID = $this->getIDFromName($textParts[1]);
906 if($toUserID === null) {
907 $this->insertChatBotMessage(
908 $this->getPrivateMessageID(),
909 '/error UserNameNotFound '.$textParts[1]
910 );
911 } else {
912 // Remove the invitation from the database:
913 $this->removeInvitation($toUserID);
914 $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel());
915 // Copy of uninvitation to current User:
916 $this->insertChatBotMessage(
917 $this->getPrivateMessageID(),
918 '/uninviteto '.$textParts[1].' '.$invitationChannelName
919 );
920 // Uninvitation to requested User:
921 $this->insertChatBotMessage(
922 $this->getPrivateMessageID($toUserID),
923 '/uninvite '.$this->getUserName().' '.$invitationChannelName
924 );
925 }
926 }
927 } else {
928 $this->insertChatBotMessage(
929 $this->getPrivateMessageID(),
930 '/error UninviteNotAllowed'
931 );
932 }
933 }
934
935 function insertParsedMessageQuery($textParts) {
936 if($this->isAllowedToSendPrivateMessage()) {
937 if(count($textParts) == 1) {
938 if($this->getQueryUserName() !== null) {
939 $this->insertChatBotMessage(
940 $this->getPrivateMessageID(),
941 '/queryClose '.$this->getQueryUserName()
942 );
943 // Close the current query:
944 $this->setQueryUserName(null);
945 } else {
946 $this->insertChatBotMessage(
947 $this->getPrivateMessageID(),
948 '/error NoOpenQuery'
949 );
950 }
951 } else {
952 if($this->getIDFromName($textParts[1]) === null) {
953 $this->insertChatBotMessage(
954 $this->getPrivateMessageID(),
955 '/error UserNameNotFound '.$textParts[1]
956 );
957 } else {
958 if($this->getQueryUserName() !== null) {
959 // Close the current query:
960 $this->insertMessage('/query');
961 }
962 // Open a query to the requested user:
963 $this->setQueryUserName($textParts[1]);
964 $this->insertChatBotMessage(
965 $this->getPrivateMessageID(),
966 '/queryOpen '.$textParts[1]
967 );
968 }
969 }
970 } else {
971 $this->insertChatBotMessage(
972 $this->getPrivateMessageID(),
973 '/error PrivateMessageNotAllowed'
974 );
975 }
976 }
977
978 function insertParsedMessageKick($textParts) {
979 // Only moderators/admins may kick users:
980 if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
981 if(count($textParts) == 1) {
982 $this->insertChatBotMessage(
983 $this->getPrivateMessageID(),
984 '/error MissingUserName'
985 );
986 } else {
987 // Get UserID from UserName:
988 $kickUserID = $this->getIDFromName($textParts[1]);
989 if($kickUserID === null) {
990 $this->insertChatBotMessage(
991 $this->getPrivateMessageID(),
992 '/error UserNameNotFound '.$textParts[1]
993 );
994 } else {
995 // Check the role of the user to kick:
996 $kickUserRole = $this->getRoleFromID($kickUserID);
997 if($kickUserRole == AJAX_CHAT_ADMIN || ($kickUserRole == AJAX_CHAT_MODERATOR && $this->getUserRole() != AJAX_CHAT_ADMIN)) {
998 // Admins and moderators may not be kicked:
999 $this->insertChatBotMessage(
1000 $this->getPrivateMessageID(),
1001 '/error KickNotAllowed '.$textParts[1]
1002 );
1003 } else {
1004 // Kick user and insert message:
1005 $channel = $this->getChannelFromID($kickUserID);
1006 $banMinutes = (count($textParts) > 2) ? $textParts[2] : null;
1007 $this->kickUser($textParts[1], $banMinutes, $kickUserID);
1008 // If no channel found, user logged out before he could be kicked
1009 if($channel !== null) {
1010 $this->insertChatBotMessage(
1011 $channel,
1012 '/kick '.$textParts[1],
1013 null,
1014 1
1015 );
1016 // Send a copy of the message to the current user, if not in the channel:
1017 if($channel != $this->getChannel()) {
1018 $this->insertChatBotMessage(
1019 $this->getPrivateMessageID(),
1020 '/kick '.$textParts[1],
1021 null,
1022 1
1023 );
1024 }
1025 }
1026 }
1027 }
1028 }
1029 } else {
1030 $this->insertChatBotMessage(
1031 $this->getPrivateMessageID(),
1032 '/error CommandNotAllowed '.$textParts[0]
1033 );
1034 }
1035 }
1036
1037 function insertParsedMessageBans($textParts) {
1038 // Only moderators/admins may see the list of banned users:
1039 if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
1040 $this->removeExpiredBans();
1041 $bannedUsers = $this->getBannedUsers();
1042 if(count($bannedUsers) > 0) {
1043 $this->insertChatBotMessage(
1044 $this->getPrivateMessageID(),
1045 '/bans '.implode(' ', $bannedUsers)
1046 );
1047 } else {
1048 $this->insertChatBotMessage(
1049 $this->getPrivateMessageID(),
1050 '/bansEmpty -'
1051 );
1052 }
1053 } else {
1054 $this->insertChatBotMessage(
1055 $this->getPrivateMessageID(),
1056 '/error CommandNotAllowed '.$textParts[0]
1057 );
1058 }
1059 }
1060
1061 function insertParsedMessageUnban($textParts) {
1062 // Only moderators/admins may unban users:
1063 if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
1064 $this->removeExpiredBans();
1065 if(count($textParts) == 1) {
1066 $this->insertChatBotMessage(
1067 $this->getPrivateMessageID(),
1068 '/error MissingUserName'
1069 );
1070 } else {
1071 if(!in_array($textParts[1], $this->getBannedUsers())) {
1072 $this->insertChatBotMessage(
1073 $this->getPrivateMessageID(),
1074 '/error UserNameNotFound '.$textParts[1]
1075 );
1076 } else {
1077 // Unban user and insert message:
1078 $this->unbanUser($textParts[1]);
1079 $this->insertChatBotMessage(
1080 $this->getPrivateMessageID(),
1081 '/unban '.$textParts[1]
1082 );
1083 }
1084 }
1085 } else {
1086 $this->insertChatBotMessage(
1087 $this->getPrivateMessageID(),
1088 '/error CommandNotAllowed '.$textParts[0]
1089 );
1090 }
1091 }
1092
1093 function insertParsedMessageAction($textParts) {
1094 if(count($textParts) == 1) {
1095 $this->insertChatBotMessage(
1096 $this->getPrivateMessageID(),
1097 '/error MissingText'
1098 );
1099 } else {
1100 if($this->getQueryUserName() !== null) {
1101 // If we are in query mode, sent the action to the query user:
1102 $this->insertMessage('/describe '.$this->getQueryUserName().' '.implode(' ', array_slice($textParts, 1)));
1103 } else {
1104 $this->insertCustomMessage(
1105 $this->getUserID(),
1106 $this->getUserName(),
1107 $this->getUserRole(),
1108 $this->getChannel(),
1109 implode(' ', $textParts)
1110 );
1111 }
1112 }
1113 }
1114
1115 function insertParsedMessageWho($textParts) {
1116 if(count($textParts) == 1) {
1117 if($this->isAllowedToListHiddenUsers()) {
1118 // List online users from any channel:
1119 $this->insertChatBotMessage(
1120 $this->getPrivateMessageID(),
1121 '/who '.implode(' ', $this->getOnlineUsers())
1122 );
1123 } else {
1124 // Get online users for all accessible channels:
1125 $channels = $this->getChannels();
1126 // Add the own private channel if allowed:
1127 if($this->isAllowedToCreatePrivateChannel()) {
1128 array_push($channels, $this->getPrivateChannelID());
1129 }
1130 // Add the invitation channels:
1131 foreach($this->getInvitations() as $channelID) {
1132 if(!in_array($channelID, $channels)) {
1133 array_push($channels, $channelID);
1134 }
1135 }
1136 $this->insertChatBotMessage(
1137 $this->getPrivateMessageID(),
1138 '/who '.implode(' ', $this->getOnlineUsers($channels))
1139 );
1140 }
1141 } else {
1142 $channelName = $textParts[1];
1143 $channelID = $this->getChannelIDFromChannelName($channelName);
1144 if(!$this->validateChannel($channelID)) {
1145 // Invalid channel:
1146 $this->insertChatBotMessage(
1147 $this->getPrivateMessageID(),
1148 '/error InvalidChannelName '.$channelName
1149 );
1150 } else {
1151 // Get online users for the given channel:
1152 $onlineUsers = $this->getOnlineUsers(array($channelID));
1153 if(count($onlineUsers) > 0) {
1154 $this->insertChatBotMessage(
1155 $this->getPrivateMessageID(),
1156 '/whoChannel '.$channelName.' '.implode(' ', $onlineUsers)
1157 );
1158 } else {
1159 $this->insertChatBotMessage(
1160 $this->getPrivateMessageID(),
1161 '/whoEmpty -'
1162 );
1163 }
1164 }
1165 }
1166 }
1167
1168 function insertParsedMessageList($textParts) {
1169 // Get the names of all accessible channels:
1170 $channelNames = $this->getChannelNames();
1171 // Add the own private channel, if allowed:
1172 if($this->isAllowedToCreatePrivateChannel()) {
1173 array_push($channelNames, $this->getPrivateChannelName());
1174 }
1175 // Add the invitation channels:
1176 foreach($this->getInvitations() as $channelID) {
1177 $channelName = $this->getChannelNameFromChannelID($channelID);
1178 if($channelName !== null && !in_array($channelName, $channelNames)) {
1179 array_push($channelNames, $channelName);
1180 }
1181 }
1182 $this->insertChatBotMessage(
1183 $this->getPrivateMessageID(),
1184 '/list '.implode(' ', $channelNames)
1185 );
1186 }
1187
1188 function insertParsedMessageWhereis($textParts) {
1189 if(count($textParts) == 1) {
1190 $this->insertChatBotMessage(
1191 $this->getPrivateMessageID(),
1192 '/error MissingUserName'
1193 );
1194 } else {
1195 // Get UserID from UserName:
1196 $whereisUserID = $this->getIDFromName($textParts[1]);
1197 if($whereisUserID === null) {
1198 $this->insertChatBotMessage(
1199 $this->getPrivateMessageID(),
1200 '/error UserNameNotFound '.$textParts[1]
1201 );
1202 } else {
1203 $channelID = $this->getChannelFromID($whereisUserID);
1204 if($this->validateChannel($channelID)) {
1205 $channelName = $this->getChannelNameFromChannelID($channelID);
1206 } else {
1207 $channelName = null;
1208 }
1209 if($channelName === null) {
1210 $this->insertChatBotMessage(
1211 $this->getPrivateMessageID(),
1212 '/error UserNameNotFound '.$textParts[1]
1213 );
1214 } else {
1215 // List user information:
1216 $this->insertChatBotMessage(
1217 $this->getPrivateMessageID(),
1218 '/whereis '.$textParts[1].' '.$channelName
1219 );
1220 }
1221 }
1222 }
1223 }
1224
1225 function insertParsedMessageWhois($textParts) {
1226 // Only moderators/admins:
1227 if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
1228 if(count($textParts) == 1) {
1229 $this->insertChatBotMessage(
1230 $this->getPrivateMessageID(),
1231 '/error MissingUserName'
1232 );
1233 } else {
1234 // Get UserID from UserName:
1235 $whoisUserID = $this->getIDFromName($textParts[1]);
1236 if($whoisUserID === null) {
1237 $this->insertChatBotMessage(
1238 $this->getPrivateMessageID(),
1239 '/error UserNameNotFound '.$textParts[1]
1240 );
1241 } else {
1242 // List user information:
1243 $this->insertChatBotMessage(
1244 $this->getPrivateMessageID(),
1245 '/whois '.$textParts[1].' '.$this->getIPFromID($whoisUserID)
1246 );
1247 }
1248 }
1249 } else {
1250 $this->insertChatBotMessage(
1251 $this->getPrivateMessageID(),
1252 '/error CommandNotAllowed '.$textParts[0]
1253 );
1254 }
1255 }
1256
1257 function insertParsedMessageRoll($textParts) {
1258 if(count($textParts) == 1) {
1259 // default is one d6:
1260 $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6);
1261 } else {
1262 $diceParts = explode('d', $textParts[1]);
1263 if(count($diceParts) == 2) {
1264 $number = (int)$diceParts[0];
1265 $sides = (int)$diceParts[1];
1266
1267 // Dice number must be an integer between 1 and 100, else roll only one:
1268 $number = ($number > 0 && $number <= 100) ? $number : 1;
1269
1270 // Sides must be an integer between 1 and 100, else take 6:
1271 $sides = ($sides > 0 && $sides <= 100) ? $sides : 6;
1272
1273 $text = '/roll '.$this->getUserName().' '.$number.'d'.$sides.' ';
1274 for($i=0; $i<$number; $i++) {
1275 if($i != 0)
1276 $text .= ',';
1277 $text .= $this->rollDice($sides);
1278 }
1279 } else {
1280 // if dice syntax is invalid, roll one d6:
1281 $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6);
1282 }
1283 }
1284 $this->insertChatBotMessage(
1285 $this->getChannel(),
1286 $text
1287 );
1288 }
1289
1290 function insertParsedMessageNick($textParts) {
1291 if(!$this->getConfig('allowNickChange') ||
1292 (!$this->getConfig('allowGuestUserName') && $this->getUserRole() == AJAX_CHAT_GUEST)) {
1293 $this->insertChatBotMessage(
1294 $this->getPrivateMessageID(),
1295 '/error CommandNotAllowed '.$textParts[0]
1296 );
1297 } else if(count($textParts) == 1) {
1298 $this->insertChatBotMessage(
1299 $this->getPrivateMessageID(),
1300 '/error MissingUserName'
1301 );
1302 } else {
1303 $newUserName = implode(' ', array_slice($textParts, 1));
1304 if($newUserName == $this->getLoginUserName()) {
1305 // Allow the user to regain the original login userName:
1306 $prefix = '';
1307 $suffix = '';
1308 } else if($this->getUserRole() == AJAX_CHAT_GUEST) {
1309 $prefix = $this->getConfig('guestUserPrefix');
1310 $suffix = $this->getConfig('guestUserSuffix');
1311 } else {
1312 $prefix = $this->getConfig('changedNickPrefix');
1313 $suffix = $this->getConfig('changedNickSuffix');
1314 }
1315 $maxLength = $this->getConfig('userNameMaxLength')
1316 - $this->stringLength($prefix)
1317 - $this->stringLength($suffix);
1318 $newUserName = $this->trimString($newUserName, 'UTF-8', $maxLength, true);
1319 if(!$newUserName) {
1320 $this->insertChatBotMessage(
1321 $this->getPrivateMessageID(),
1322 '/error InvalidUserName'
1323 );
1324 } else {
1325 $newUserName = $prefix.$newUserName.$suffix;
1326 if($this->isUserNameInUse($newUserName)) {
1327 $this->insertChatBotMessage(
1328 $this->getPrivateMessageID(),
1329 '/error UserNameInUse'
1330 );
1331 } else {
1332 $oldUserName = $this->getUserName();
1333 $this->setUserName($newUserName);
1334 $this->updateOnlineList();
1335 // Add info message to update the client-side stored userName:
1336 $this->addInfoMessage($this->getUserName(), 'userName');
1337 $this->insertChatBotMessage(
1338 $this->getChannel(),
1339 '/nick '.$oldUserName.' '.$newUserName,
1340 null,
1341 2
1342 );
1343 }
1344 }
1345 }
1346 }
1347
1348 function insertMessage($text) {
1349 if(!$this->isAllowedToWriteMessage())
1350 return;
1351
1352 if(!$this->floodControl())
1353 return;
1354
1355 $text = $this->trimMessageText($text);
1356 if($text == '')
1357 return;
1358
1359 if(!$this->onNewMessage($text))
1360 return;
1361
1362 $text = $this->replaceCustomText($text);
1363
1364 $this->insertParsedMessage($text);
1365 }
1366
1367 function deleteMessage($messageID) {
1368 // Retrieve the channel of the given message:
1369 $sql = 'SELECT
1370 channel
1371 FROM
1372 '.$this->getDataBaseTable('messages').'
1373 WHERE
1374 id='.$this->db->makeSafe($messageID).';';
1375
1376 // Create a new SQL query:
1377 $result = $this->db->sqlQuery($sql);
1378
1379 // Stop if an error occurs:
1380 if($result->error()) {
1381 echo $result->getError();
1382 die();
1383 }
1384
1385 $row = $result->fetch();
1386
1387 if($row['channel'] !== null) {
1388 $channel = $row['channel'];
1389
1390 if($this->getUserRole() == AJAX_CHAT_ADMIN) {
1391 $condition = '';
1392 } else if($this->getUserRole() == AJAX_CHAT_MODERATOR) {
1393 $condition = ' AND
1394 NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).')
1395 AND
1396 NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')';
1397 } else if($this->getUserRole() == AJAX_CHAT_USER && $this->getConfig('allowUserMessageDelete')) {
1398 $condition = 'AND
1399 (
1400 userID='.$this->db->makeSafe($this->getUserID()).'
1401 OR
1402 (
1403 channel = '.$this->db->makeSafe($this->getPrivateMessageID()).'
1404 OR
1405 channel = '.$this->db->makeSafe($this->getPrivateChannelID()).'
1406 )
1407 AND
1408 NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).')
1409 AND
1410 NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')
1411 )';
1412 } else {
1413 return false;
1414 }
1415
1416 // Remove given message from the database:
1417 $sql = 'DELETE FROM
1418 '.$this->getDataBaseTable('messages').'
1419 WHERE
1420 id='.$this->db->makeSafe($messageID).'
1421 '.$condition.';';
1422
1423 // Create a new SQL query:
1424 $result = $this->db->sqlQuery($sql);
1425
1426 // Stop if an error occurs:
1427 if($result->error()) {
1428 echo $result->getError();
1429 die();
1430 }
1431
1432 if($result->affectedRows() == 1) {
1433 // Insert a deletion command to remove the message from the clients chatlists:
1434 $this->insertChatBotMessage($channel, '/delete '.$messageID);
1435 return true;
1436 }
1437 }
1438 return false;
1439 }
1440
1441 function floodControl() {
1442 // Moderators and Admins need no flood control:
1443 if($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_ADMIN) {
1444 return true;
1445 }
1446 $time = time();
1447 // Check the time of the last inserted message:
1448 if($this->getInsertedMessagesRateTimeStamp()+60 < $time) {
1449 $this->setInsertedMessagesRateTimeStamp($time);
1450 $this->setInsertedMessagesRate(1);
1451 } else {
1452 // Increase the inserted messages rate:
1453 $rate = $this->getInsertedMessagesRate()+1;
1454 $this->setInsertedMessagesRate($rate);
1455 // Check if message rate is too high:
1456 if($rate > $this->getConfig('maxMessageRate')) {
1457 $this->insertChatBotMessage(
1458 $this->getPrivateMessageID(),
1459 '/error MaxMessageRate'
1460 );
1461 // Return false so the message is not inserted:
1462 return false;
1463 }
1464 }
1465 return true;
1466 }
1467
1468 function isAllowedToWriteMessage() {
1469 if($this->getUserRole() != AJAX_CHAT_GUEST)
1470 return true;
1471 if($this->getConfig('allowGuestWrite'))
1472 return true;
1473 return false;
1474 }
1475
1476 function insertChatBotMessage($channelID, $messageText, $ip=null, $mode=0) {
1477 $this->insertCustomMessage(
1478 $this->getConfig('chatBotID'),
1479 $this->getConfig('chatBotName'),
1480 AJAX_CHAT_CHATBOT,
1481 $channelID,
1482 $messageText,
1483 $ip,
1484 $mode
1485 );
1486 }
1487
1488 function insertCustomMessage($userID, $userName, $userRole, $channelID, $text, $ip=null, $mode=0) {
1489 // The $mode parameter is used for socket updates:
1490 // 0 = normal messages
1491 // 1 = channel messages (e.g. login/logout, channel enter/leave, kick)
1492 // 2 = messages with online user updates (nick)
1493
1494 $ip = $ip ? $ip : $_SERVER['REMOTE_ADDR'];
1495
1496 $sql = 'INSERT INTO '.$this->getDataBaseTable('messages').'(
1497 userID,
1498 userName,
1499 userRole,
1500 channel,
1501 dateTime,
1502 ip,
1503 text
1504 )
1505 VALUES (
1506 '.$this->db->makeSafe($userID).',
1507 '.$this->db->makeSafe($userName).',
1508 '.$this->db->makeSafe($userRole).',
1509 '.$this->db->makeSafe($channelID).',
1510 NOW(),
1511 '.$this->db->makeSafe($this->ipToStorageFormat($ip)).',
1512 '.$this->db->makeSafe($text).'
1513 );';
1514
1515 // Create a new SQL query:
1516 $result = $this->db->sqlQuery($sql);
1517
1518 // Stop if an error occurs:
1519 if($result->error()) {
1520 echo $result->getError();
1521 die();
1522 }
1523
1524 if($this->getConfig('socketServerEnabled')) {
1525 $this->sendSocketMessage(
1526 $this->getSocketBroadcastMessage(
1527 $this->db->getLastInsertedID(),
1528 time(),
1529 $userID,
1530 $userName,
1531 $userRole,
1532 $channelID,
1533 $text,
1534 $mode
1535 )
1536 );
1537 }
1538 }
1539
1540 function getSocketBroadcastMessage(
1541 $messageID,
1542 $timeStamp,
1543 $userID,
1544 $userName,
1545 $userRole,
1546 $channelID,
1547 $text,
1548 $mode
1549 ) {
1550 // The $mode parameter:
1551 // 0 = normal messages
1552 // 1 = channel messages (e.g. login/logout, channel enter/leave, kick)
1553 // 2 = messages with online user updates (nick)
1554
1555 // Get the message XML content:
1556 $xml = '<root chatID="'.$this->getConfig('socketServerChatID').'" channelID="'.$channelID.'" mode="'.$mode.'">';
1557 if($mode) {
1558 // Add the list of online users if the user list has been updated ($mode > 0):
1559 $xml .= $this->getChatViewOnlineUsersXML(array($channelID));
1560 }
1561 if($mode != 1 || $this->getConfig('showChannelMessages')) {
1562 $xml .= '<messages>';
1563 $xml .= $this->getChatViewMessageXML(
1564 $messageID,
1565 $timeStamp,
1566 $userID,
1567 $userName,
1568 $userRole,
1569 $channelID,
1570 $text
1571 );
1572 $xml .= '</messages>';
1573 }
1574 $xml .= '</root>';
1575 return $xml;
1576 }
1577
1578 function sendSocketMessage($message) {
1579 // Open a TCP socket connection to the socket server:
1580 if($socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
1581 if(@socket_connect($socket, $this->getConfig('socketServerIP'), $this->getConfig('socketServerPort'))) {
1582 // Append a null-byte to the string as EOL (End Of Line) character
1583 // which is required by Flash XML socket communication:
1584 $message .= "\0";
1585 @socket_write(
1586 $socket,
1587 $message,
1588 strlen($message) // Using strlen to count the bytes instead of the number of UTF-8 characters
1589 );
1590 }
1591 @socket_close($socket);
1592 }
1593 }
1594
1595 function updateSocketAuthentication($userID, $socketRegistrationID=null, $channels=null) {
1596 // If no $socketRegistrationID or no $channels are given the authentication is removed for the given user:
1597 $authentication = '<authenticate chatID="'.$this->getConfig('socketServerChatID').'" userID="'.$userID.'" regID="'.$socketRegistrationID.'">';
1598 if($channels) {
1599 foreach($channels as $channelID) {
1600 $authentication .= '<channel id="'.$channelID.'"/>';
1601 }
1602 }
1603 $authentication .= '</authenticate>';
1604 $this->sendSocketMessage($authentication);
1605 }
1606
1607 function setSocketRegistrationID($value) {
1608 $this->setSessionVar('SocketRegistrationID', $value);
1609 }
1610
1611 function getSocketRegistrationID() {
1612 return $this->getSessionVar('SocketRegistrationID');
1613 }
1614
1615 function rollDice($sides) {
1616 return mt_rand(1, $sides);
1617 }
1618
1619 function kickUser($userName, $banMinutes=null, $userID=null) {
1620 if($userID === null) {
1621 $userID = $this->getIDFromName($userName);
1622 }
1623 if($userID === null) {
1624 return;
1625 }
1626
1627 $banMinutes = ($banMinutes !== null) ? $banMinutes : $this->getConfig('defaultBanTime');
1628
1629 if($banMinutes) {
1630 // Ban User for the given time in minutes:
1631 $this->banUser($userName, $banMinutes, $userID);
1632 }
1633
1634 // Remove given User from online list:
1635 $sql = 'DELETE FROM
1636 '.$this->getDataBaseTable('online').'
1637 WHERE
1638 userID = '.$this->db->makeSafe($userID).';';
1639
1640 // Create a new SQL query:
1641 $result = $this->db->sqlQuery($sql);
1642
1643 // Stop if an error occurs:
1644 if($result->error()) {
1645 echo $result->getError();
1646 die();
1647 }
1648
1649 // Update the socket server authentication for the kicked user:
1650 if($this->getConfig('socketServerEnabled')) {
1651 $this->updateSocketAuthentication($userID);
1652 }
1653
1654 $this->removeUserFromOnlineUsersData($userID);
1655 }
1656
1657 function getBannedUsersData($key=null, $value=null) {
1658 if($this->_bannedUsersData === null) {
1659 $this->_bannedUsersData = array();
1660
1661 $sql = 'SELECT
1662 userID,
1663 userName,
1664 ip
1665 FROM
1666 '.$this->getDataBaseTable('bans').'
1667 WHERE
1668 NOW() < dateTime;';
1669
1670 // Create a new SQL query:
1671 $result = $this->db->sqlQuery($sql);
1672
1673 // Stop if an error occurs:
1674 if($result->error()) {
1675 echo $result->getError();
1676 die();
1677 }
1678
1679 while($row = $result->fetch()) {
1680 $row['ip'] = $this->ipFromStorageFormat($row['ip']);
1681 array_push($this->_bannedUsersData, $row);
1682 }
1683
1684 $result->free();
1685 }
1686
1687 if($key) {
1688 $bannedUsersData = array();
1689 foreach($this->_bannedUsersData as $bannedUserData) {
1690 if(!isset($bannedUserData[$key])) {
1691 return $bannedUsersData;
1692 }
1693 if($value) {
1694 if($bannedUserData[$key] == $value) {
1695 array_push($bannedUsersData, $bannedUserData);
1696 } else {
1697 continue;
1698 }
1699 } else {
1700 array_push($bannedUsersData, $bannedUserData[$key]);
1701 }
1702 }
1703 return $bannedUsersData;
1704 }
1705
1706 return $this->_bannedUsersData;
1707 }
1708
1709 function getBannedUsers() {
1710 return $this->getBannedUsersData('userName');
1711 }
1712
1713 function banUser($userName, $banMinutes=null, $userID=null) {
1714 if($userID === null) {
1715 $userID = $this->getIDFromName($userName);
1716 }
1717 $ip = $this->getIPFromID($userID);
1718 if(!$ip || $userID === null) {
1719 return;
1720 }
1721
1722 // Remove expired bans:
1723 $this->removeExpiredBans();
1724
1725 $banMinutes = (int)$banMinutes;
1726 if(!$banMinutes) {
1727 // If banMinutes is not a valid integer, use the defaultBanTime:
1728 $banMinutes = $this->getConfig('defaultBanTime');
1729 }
1730
1731 $sql = 'INSERT INTO '.$this->getDataBaseTable('bans').'(
1732 userID,
1733 userName,
1734 dateTime,
1735 ip
1736 )
1737 VALUES (
1738 '.$this->db->makeSafe($userID).',
1739 '.$this->db->makeSafe($userName).',
1740 DATE_ADD(NOW(), interval '.$this->db->makeSafe($banMinutes).' MINUTE),
1741 '.$this->db->makeSafe($this->ipToStorageFormat($ip)).'
1742 );';
1743
1744 // Create a new SQL query:
1745 $result = $this->db->sqlQuery($sql);
1746
1747 // Stop if an error occurs:
1748 if($result->error()) {
1749 echo $result->getError();
1750 die();
1751 }
1752 }
1753
1754 function unbanUser($userName) {
1755 $sql = 'DELETE FROM
1756 '.$this->getDataBaseTable('bans').'
1757 WHERE
1758 userName = '.$this->db->makeSafe($userName).';';
1759
1760 // Create a new SQL query:
1761 $result = $this->db->sqlQuery($sql);
1762
1763 // Stop if an error occurs:
1764 if($result->error()) {
1765 echo $result->getError();
1766 die();
1767 }
1768 }
1769
1770 function removeExpiredBans() {
1771 $sql = 'DELETE FROM
1772 '.$this->getDataBaseTable('bans').'
1773 WHERE
1774 dateTime < NOW();';
1775
1776 // Create a new SQL query:
1777 $result = $this->db->sqlQuery($sql);
1778
1779 // Stop if an error occurs:
1780 if($result->error()) {
1781 echo $result->getError();
1782 die();
1783 }
1784 }
1785
1786 function setInactive($userID, $userName=null) {
1787 $condition = 'userID='.$this->db->makeSafe($userID);
1788 if($userName !== null) {
1789 $condition .= ' OR userName='.$this->db->makeSafe($userName);
1790 }
1791 $sql = 'UPDATE
1792 '.$this->getDataBaseTable('online').'
1793 SET
1794 dateTime = DATE_SUB(NOW(), interval '.(intval($this->getConfig('inactiveTimeout'))+1).' MINUTE)
1795 WHERE
1796 '.$condition.';';
1797
1798 // Create a new SQL query:
1799 $result = $this->db->sqlQuery($sql);
1800
1801 // Stop if an error occurs:
1802 if($result->error()) {
1803 echo $result->getError();
1804 die();
1805 }
1806
1807 $this->resetOnlineUsersData();
1808 }
1809
1810 function removeInactive() {
1811 $sql = 'SELECT
1812 userID,
1813 userName,
1814 channel
1815 FROM
1816 '.$this->getDataBaseTable('online').'
1817 WHERE
1818 NOW() > DATE_ADD(dateTime, interval '.$this->getConfig('inactiveTimeout').' MINUTE);';
1819
1820 // Create a new SQL query:
1821 $result = $this->db->sqlQuery($sql);
1822
1823 // Stop if an error occurs:
1824 if($result->error()) {
1825 echo $result->getError();
1826 die();
1827 }
1828
1829 if($result->numRows() > 0) {
1830 $condition = '';
1831 while($row = $result->fetch()) {
1832 if(!empty($condition))
1833 $condition .= ' OR ';
1834 // Add userID to condition for removal:
1835 $condition .= 'userID='.$this->db->makeSafe($row['userID']);
1836
1837 // Update the socket server authentication for the kicked user:
1838 if($this->getConfig('socketServerEnabled')) {
1839 $this->updateSocketAuthentication($row['userID']);
1840 }
1841
1842 $this->removeUserFromOnlineUsersData($row['userID']);
1843
1844 // Insert logout timeout message:
1845 $text = '/logout '.$row['userName'].' Timeout';
1846 $this->insertChatBotMessage(
1847 $row['channel'],
1848 $text,
1849 null,
1850 1
1851 );
1852 }
1853
1854 $result->free();
1855
1856 $sql = 'DELETE FROM
1857 '.$this->getDataBaseTable('online').'
1858 WHERE
1859 '.$condition.';';
1860
1861 // Create a new SQL query:
1862 $result = $this->db->sqlQuery($sql);
1863
1864 // Stop if an error occurs:
1865 if($result->error()) {
1866 echo $result->getError();
1867 die();
1868 }
1869 }
1870 }
1871
1872 function updateOnlineStatus() {
1873 // Update online status every 50 seconds (this allows update requests to be in time):
1874 if(!$this->getStatusUpdateTimeStamp() || ((time() - $this->getStatusUpdateTimeStamp()) > 50)) {
1875 $this->updateOnlineList();
1876 $this->setStatusUpdateTimeStamp(time());
1877 }
1878 }
1879
1880 function checkAndRemoveInactive() {
1881 // Remove inactive users every inactiveCheckInterval:
1882 if(!$this->getInactiveCheckTimeStamp() || ((time() - $this->getInactiveCheckTimeStamp()) > $this->getConfig('inactiveCheckInterval')*60)) {
1883 $this->removeInactive();
1884 $this->setInactiveCheckTimeStamp(time());
1885 }
1886 }
1887
1888 function sendXMLMessages() {
1889 $httpHeader = new AJAXChatHTTPHeader('UTF-8', 'text/xml');
1890
1891 // Send HTTP header:
1892 $httpHeader->send();
1893
1894 // Output XML messages:
1895 echo $this->getXMLMessages();
1896 }
1897
1898 function getXMLMessages() {
1899 switch($this->getView()) {
1900 case 'chat':
1901 return $this->getChatViewXMLMessages();
1902 case 'teaser':
1903 return $this->getTeaserViewXMLMessages();
1904 case 'logs':
1905 return $this->getLogsViewXMLMessages();
1906 default:
1907 return $this->getLogoutXMLMessage();
1908 }
1909 }
1910
1911 function getMessageCondition() {
1912 $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')).'
1913 AND (
1914 channel = '.$this->db->makeSafe($this->getChannel()).'
1915 OR
1916 channel = '.$this->db->makeSafe($this->getPrivateMessageID()).'
1917 )
1918 AND
1919 ';
1920 if($this->getConfig('requestMessagesPriorChannelEnter') ||
1921 ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($this->getChannel(), $this->getConfig('requestMessagesPriorChannelEnterList')))) {
1922 $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)';
1923 } else {
1924 $condition .= 'dateTime >= FROM_UNIXTIME(' . $this->getChannelEnterTimeStamp() . ')';
1925 }
1926 return $condition;
1927 }
1928
1929 function getMessageFilter() {
1930 $filterChannelMessages = '';
1931 if(!$this->getConfig('showChannelMessages') || $this->getRequestVar('shoutbox')) {
1932 $filterChannelMessages = ' AND NOT (
1933 text LIKE (\'/login%\')
1934 OR
1935 text LIKE (\'/logout%\')
1936 OR
1937 text LIKE (\'/channelEnter%\')
1938 OR
1939 text LIKE (\'/channelLeave%\')
1940 OR
1941 text LIKE (\'/kick%\')
1942 )';
1943 }
1944 return $filterChannelMessages;
1945 }
1946
1947 function getInfoMessagesXML() {
1948 $xml = '<infos>';
1949 // Go through the info messages:
1950 foreach($this->getInfoMessages() as $type=>$infoArray) {
1951 foreach($infoArray as $info) {
1952 $xml .= '<info type="'.$type.'">';
1953 $xml .= '<![CDATA['.$this->encodeSpecialChars($info).']]>';
1954 $xml .= '</info>';
1955 }
1956 }
1957 $xml .= '</infos>';
1958 return $xml;
1959 }
1960
1961 function getChatViewOnlineUsersXML($channelIDs) {
1962 // Get the online users for the given channels:
1963 $onlineUsersData = $this->getOnlineUsersData($channelIDs);
1964 $xml = '<users>';
1965 foreach($onlineUsersData as $onlineUserData) {
1966 $xml .= '<user';
1967 $xml .= ' userID="'.$onlineUserData['userID'].'"';
1968 $xml .= ' userRole="'.$onlineUserData['userRole'].'"';
1969 $xml .= ' channelID="'.$onlineUserData['channel'].'"';
1970 $xml .= '>';
1971 $xml .= '<![CDATA['.$this->encodeSpecialChars($onlineUserData['userName']).']]>';
1972 $xml .= '</user>';
1973 }
1974 $xml .= '</users>';
1975 return $xml;
1976 }
1977
1978 function getLogoutXMLMessage() {
1979 $xml = '<?xml version="1.0" encoding="UTF-8"?>';
1980 $xml .= '<root>';
1981 $xml .= '<infos>';
1982 $xml .= '<info type="logout">';
1983 $xml .= '<![CDATA['.$this->encodeSpecialChars($this->getConfig('logoutData')).']]>';
1984 $xml .= '</info>';
1985 $xml .= '</infos>';
1986 $xml .= '</root>';
1987 return $xml;
1988 }
1989
1990 function getChatViewMessageXML(
1991 $messageID,
1992 $timeStamp,
1993 $userID,
1994 $userName,
1995 $userRole,
1996 $channelID,
1997 $text
1998 ) {
1999 $message = '<message';
2000 $message .= ' id="'.$messageID.'"';
2001 $message .= ' dateTime="'.date('r', $timeStamp).'"';
2002 $message .= ' userID="'.$userID.'"';
2003 $message .= ' userRole="'.$userRole.'"';
2004 $message .= ' channelID="'.$channelID.'"';
2005 $message .= '>';
2006 $message .= '<username><![CDATA['.$this->encodeSpecialChars($userName).']]></username>';
2007 $message .= '<text><![CDATA['.$this->encodeSpecialChars($text).']]></text>';
2008 $message .= '</message>';
2009 return $message;
2010 }
2011
2012 function getChatViewMessagesXML() {
2013 // Get the last messages in descending order (this optimises the LIMIT usage):
2014 $sql = 'SELECT
2015 id,
2016 userID,
2017 userName,
2018 userRole,
2019 channel AS channelID,
2020 UNIX_TIMESTAMP(dateTime) AS timeStamp,
2021 text
2022 FROM
2023 '.$this->getDataBaseTable('messages').'
2024 WHERE
2025 '.$this->getMessageCondition().'
2026 '.$this->getMessageFilter().'
2027 ORDER BY
2028 id
2029 DESC
2030 LIMIT '.$this->getConfig('requestMessagesLimit').';';
2031
2032 // Create a new SQL query:
2033 $result = $this->db->sqlQuery($sql);
2034
2035 // Stop if an error occurs:
2036 if($result->error()) {
2037 echo $result->getError();
2038 die();
2039 }
2040
2041 $messages = '';
2042
2043 // Add the messages in reverse order so it is ascending again:
2044 while($row = $result->fetch()) {
2045 $message = $this->getChatViewMessageXML(
2046 $row['id'],
2047 $row['timeStamp'],
2048 $row['userID'],
2049 $row['userName'],
2050 $row['userRole'],
2051 $row['channelID'],
2052 $row['text']
2053 );
2054 $messages = $message.$messages;
2055 }
2056 $result->free();
2057
2058 $messages = '<messages>'.$messages.'</messages>';
2059 return $messages;
2060 }
2061
2062 function getChatViewXMLMessages() {
2063 $xml = '<?xml version="1.0" encoding="UTF-8"?>';
2064 $xml .= '<root>';
2065 $xml .= $this->getInfoMessagesXML();
2066 $xml .= $this->getChatViewOnlineUsersXML(array($this->getChannel()));
2067 $xml .= $this->getChatViewMessagesXML();
2068 $xml .= '</root>';
2069 return $xml;
2070 }
2071
2072 function getTeaserMessageCondition() {
2073 $channelID = $this->getValidRequestChannelID();
2074 $condition = 'channel = '.$this->db->makeSafe($channelID).'
2075 AND
2076 ';
2077 if($this->getConfig('requestMessagesPriorChannelEnter') ||
2078 ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($channelID, $this->getConfig('requestMessagesPriorChannelEnterList')))) {
2079 $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)';
2080 } else {
2081 // Teaser content may not be shown for this channel:
2082 $condition .= '0 = 1';
2083 }
2084 return $condition;
2085 }
2086
2087 function getTeaserViewMessagesXML() {
2088 // Get the last messages in descending order (this optimises the LIMIT usage):
2089 $sql = 'SELECT
2090 id,
2091 userID,
2092 userName,
2093 userRole,
2094 channel AS channelID,
2095 UNIX_TIMESTAMP(dateTime) AS timeStamp,
2096 text
2097 FROM
2098 '.$this->getDataBaseTable('messages').'
2099 WHERE
2100 '.$this->getTeaserMessageCondition().'
2101 '.$this->getMessageFilter().'
2102 ORDER BY
2103 id
2104 DESC
2105 LIMIT '.$this->getConfig('requestMessagesLimit').';';
2106
2107 // Create a new SQL query:
2108 $result = $this->db->sqlQuery($sql);
2109
2110 // Stop if an error occurs:
2111 if($result->error()) {
2112 echo $result->getError();
2113 die();
2114 }
2115
2116 $messages = '';
2117
2118 // Add the messages in reverse order so it is ascending again:
2119 while($row = $result->fetch()) {
2120 $message = '';
2121 $message .= '<message';
2122 $message .= ' id="'.$row['id'].'"';
2123 $message .= ' dateTime="'.date('r', $row['timeStamp']).'"';
2124 $message .= ' userID="'.$row['userID'].'"';
2125 $message .= ' userRole="'.$row['userRole'].'"';
2126 $message .= ' channelID="'.$row['channelID'].'"';
2127 $message .= '>';
2128 $message .= '<username><![CDATA['.$this->encodeSpecialChars($row['userName']).']]></username>';
2129 $message .= '<text><![CDATA['.$this->encodeSpecialChars($row['text']).']]></text>';
2130 $message .= '</message>';
2131 $messages = $message.$messages;
2132 }
2133 $result->free();
2134
2135 $messages = '<messages>'.$messages.'</messages>';
2136 return $messages;
2137 }
2138
2139 function getTeaserViewXMLMessages() {
2140 $xml = '<?xml version="1.0" encoding="UTF-8"?>';
2141 $xml .= '<root>';
2142 $xml .= $this->getInfoMessagesXML();
2143 $xml .= $this->getTeaserViewMessagesXML();
2144 $xml .= '</root>';
2145 return $xml;
2146 }
2147
2148 function getLogsViewCondition() {
2149 $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID'));
2150
2151 // Check the channel condition:
2152 switch($this->getRequestVar('channelID')) {
2153 case '-3':
2154 // Just display messages from all accessible channels
2155 if($this->getUserRole() != AJAX_CHAT_ADMIN) {
2156 $condition .= ' AND (channel = '.$this->db->makeSafe($this->getPrivateMessageID());
2157 $condition .= ' OR channel = '.$this->db->makeSafe($this->getPrivateChannelID());
2158 foreach($this->getChannels() as $channel) {
2159 if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) {
2160 continue;
2161 }
2162 $condition .= ' OR channel = '.$this->db->makeSafe($channel);
2163 }
2164 $condition .= ')';
2165 }
2166 break;
2167 case '-2':
2168 if($this->getUserRole() != AJAX_CHAT_ADMIN) {
2169 $condition .= ' AND channel = '.($this->getPrivateMessageID());
2170 } else {
2171 $condition .= ' AND channel > '.($this->getConfig('privateMessageDiff')-1);
2172 }
2173 break;
2174 case '-1':
2175 if($this->getUserRole() != AJAX_CHAT_ADMIN) {
2176 $condition .= ' AND channel = '.($this->getPrivateChannelID());
2177 } else {
2178 $condition .= ' AND (channel > '.($this->getConfig('privateChannelDiff')-1).' AND channel < '.($this->getConfig('privateMessageDiff')).')';
2179 }
2180 break;
2181 default:
2182 if(($this->getUserRole() == AJAX_CHAT_ADMIN || !$this->getConfig('logsUserAccessChannelList') || in_array($this->getRequestVar('channelID'), $this->getConfig('logsUserAccessChannelList')))
2183 && $this->validateChannel($this->getRequestVar('channelID'))) {
2184 $condition .= ' AND channel = '.$this->db->makeSafe($this->getRequestVar('channelID'));
2185 } else {
2186 // No valid channel:
2187 $condition .= ' AND 0 = 1';
2188 }
2189 }
2190
2191 // Check the period condition:
2192 $hour = ($this->getRequestVar('hour') === null || $this->getRequestVar('hour') > 23 || $this->getRequestVar('hour') < 0) ? null : $this->getRequestVar('hour');
2193 $day = ($this->getRequestVar('day') === null || $this->getRequestVar('day') > 31 || $this->getRequestVar('day') < 1) ? null : $this->getRequestVar('day');
2194 $month = ($this->getRequestVar('month') === null || $this->getRequestVar('month') > 12 || $this->getRequestVar('month') < 1) ? null : $this->getRequestVar('month');
2195 $year = ($this->getRequestVar('year') === null || $this->getRequestVar('year') > date('Y') || $this->getRequestVar('year') < $this->getConfig('logsFirstYear')) ? null : $this->getRequestVar('year');
2196
2197 // If a time (hour) is given but no date (year, month, day), use the current date:
2198 if($hour !== null) {
2199 if($day === null)
2200 $day = date('j');
2201 if($month === null)
2202 $month = date('n');
2203 if($year === null)
2204 $year = date('Y');
2205 }
2206
2207 if($year === null) {
2208 // No year given, so no period condition
2209 } else if($month === null) {
2210 // Define the given year as period:
2211 $periodStart = mktime(0, 0, 0, 1, 1, $year);
2212 // The last day in a month can be expressed by using 0 for the day of the next month:
2213 $periodEnd = mktime(23, 59, 59, 13, 0, $year);
2214 } else if($day === null) {
2215 // Define the given month as period:
2216 $periodStart = mktime(0, 0, 0, $month, 1, $year);
2217 // The last day in a month can be expressed by using 0 for the day of the next month:
2218 $periodEnd = mktime(23, 59, 59, $month+1, 0, $year);
2219 } else if($hour === null){
2220 // Define the given day as period:
2221 $periodStart = mktime(0, 0, 0, $month, $day, $year);
2222 $periodEnd = mktime(23, 59, 59, $month, $day, $year);
2223 } else {
2224 // Define the given hour as period:
2225 $periodStart = mktime($hour, 0, 0, $month, $day, $year);
2226 $periodEnd = mktime($hour, 59, 59, $month, $day, $year);
2227 }
2228
2229 if(isset($periodStart))
2230 $condition .= ' AND dateTime > \''.date('Y-m-d H:i:s', $periodStart).'\' AND dateTime <= \''.date('Y-m-d H:i:s', $periodEnd).'\'';
2231
2232 // Check the search condition:
2233 if($this->getRequestVar('search')) {
2234 if(($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) && strpos($this->getRequestVar('search'), 'ip=') === 0) {
2235 // Search for messages with the given IP:
2236 $ip = substr($this->getRequestVar('search'), 3);
2237 $condition .= ' AND (ip = '.$this->db->makeSafe($this->ipToStorageFormat($ip)).')';
2238 } else if(strpos($this->getRequestVar('search'), 'userID=') === 0) {
2239 // Search for messages with the given userID:
2240 $userID = substr($this->getRequestVar('search'), 7);
2241 $condition .= ' AND (userID = '.$this->db->makeSafe($userID).')';
2242 } else {
2243 // Use the search value as regular expression on message text and username:
2244 $condition .= ' AND (userName REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).' OR text REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).')';
2245 }
2246 }
2247
2248 // If no period or search condition is given, just monitor the last messages on the given channel:
2249 if(!isset($periodStart) && !$this->getRequestVar('search')) {
2250 $condition .= ' AND NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('logsRequestMessagesTimeDiff').' HOUR)';
2251 }
2252
2253 return $condition;
2254 }
2255
2256 function getLogsViewMessagesXML() {
2257 $sql = 'SELECT
2258 id,
2259 userID,
2260 userName,
2261 userRole,
2262 channel AS channelID,
2263 UNIX_TIMESTAMP(dateTime) AS timeStamp,
2264 ip,
2265 text
2266 FROM
2267 '.$this->getDataBaseTable('messages').'
2268 WHERE
2269 '.$this->getLogsViewCondition().'
2270 ORDER BY
2271 id
2272 LIMIT '.$this->getConfig('logsRequestMessagesLimit').';';
2273
2274 // Create a new SQL query:
2275 $result = $this->db->sqlQuery($sql);
2276
2277 // Stop if an error occurs:
2278 if($result->error()) {
2279 echo $result->getError();
2280 die();
2281 }
2282
2283 $xml = '<messages>';
2284 while($row = $result->fetch()) {
2285 $xml .= '<message';
2286 $xml .= ' id="'.$row['id'].'"';
2287 $xml .= ' dateTime="'.date('r', $row['timeStamp']).'"';
2288 $xml .= ' userID="'.$row['userID'].'"';
2289 $xml .= ' userRole="'.$row['userRole'].'"';
2290 $xml .= ' channelID="'.$row['channelID'].'"';
2291 if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
2292 $xml .= ' ip="'.$this->ipFromStorageFormat($row['ip']).'"';
2293 }
2294 $xml .= '>';
2295 $xml .= '<username><![CDATA['.$this->encodeSpecialChars($row['userName']).']]></username>';
2296 $xml .= '<text><![CDATA['.$this->encodeSpecialChars($row['text']).']]></text>';
2297 $xml .= '</message>';
2298 }
2299 $result->free();
2300
2301 $xml .= '</messages>';
2302
2303 return $xml;
2304 }
2305
2306 function getLogsViewXMLMessages() {
2307 $xml = '<?xml version="1.0" encoding="UTF-8"?>';
2308 $xml .= '<root>';
2309 $xml .= $this->getInfoMessagesXML();
2310 $xml .= $this->getLogsViewMessagesXML();
2311 $xml .= '</root>';
2312 return $xml;
2313 }
2314
2315 function purgeLogs() {
2316 $sql = 'DELETE FROM
2317 '.$this->getDataBaseTable('messages').'
2318 WHERE
2319 dateTime < DATE_SUB(NOW(), interval '.$this->getConfig('logsPurgeTimeDiff').' DAY);';
2320
2321 // Create a new SQL query:
2322 $result = $this->db->sqlQuery($sql);
2323
2324 // Stop if an error occurs:
2325 if($result->error()) {
2326 echo $result->getError();
2327 die();
2328 }
2329 }
2330
2331 function getInfoMessages($type=null) {
2332 if(!isset($this->_infoMessages)) {
2333 $this->_infoMessages = array();
2334 }
2335 if($type) {
2336 if(!isset($this->_infoMessages[$type])) {
2337 $this->_infoMessages[$type] = array();
2338 }
2339 return $this->_infoMessages[$type];
2340 } else {
2341 return $this->_infoMessages;
2342 }
2343 }
2344
2345 function addInfoMessage($info, $type='error') {
2346 if(!isset($this->_infoMessages)) {
2347 $this->_infoMessages = array();
2348 }
2349 if(!isset($this->_infoMessages[$type])) {
2350 $this->_infoMessages[$type] = array();
2351 }
2352 if(!in_array($info, $this->_infoMessages[$type])) {
2353 array_push($this->_infoMessages[$type], $info);
2354 }
2355 }
2356
2357 function getRequestVars() {
2358 return $this->_requestVars;
2359 }
2360
2361 function getRequestVar($key) {
2362 if($this->_requestVars && isset($this->_requestVars[$key])) {
2363 return $this->_requestVars[$key];
2364 }
2365 return null;
2366 }
2367
2368 function setRequestVar($key, $value) {
2369 if(!$this->_requestVars) {
2370 $this->_requestVars = array();
2371 }
2372 $this->_requestVars[$key] = $value;
2373 }
2374
2375 function getOnlineUsersData($channelIDs=null, $key=null, $value=null) {
2376 if($this->_onlineUsersData === null) {
2377 $this->_onlineUsersData = array();
2378
2379 $sql = 'SELECT
2380 userID,
2381 userName,
2382 userRole,
2383 channel,
2384 UNIX_TIMESTAMP(dateTime) AS timeStamp,
2385 ip
2386 FROM
2387 '.$this->getDataBaseTable('online').'
2388 ORDER BY
2389 LOWER(userName);';
2390
2391 // Create a new SQL query:
2392 $result = $this->db->sqlQuery($sql);
2393
2394 // Stop if an error occurs:
2395 if($result->error()) {
2396 echo $result->getError();
2397 die();
2398 }
2399
2400 while($row = $result->fetch()) {
2401 $row['ip'] = $this->ipFromStorageFormat($row['ip']);
2402 array_push($this->_onlineUsersData, $row);
2403 }
2404
2405 $result->free();
2406 }
2407
2408 if($channelIDs || $key) {
2409 $onlineUsersData = array();
2410 foreach($this->_onlineUsersData as $userData) {
2411 if($channelIDs && !in_array($userData['channel'], $channelIDs)) {
2412 continue;
2413 }
2414 if($key) {
2415 if(!isset($userData[$key])) {
2416 return $onlineUsersData;
2417 }
2418 if($value !== null) {
2419 if($userData[$key] == $value) {
2420 array_push($onlineUsersData, $userData);
2421 } else {
2422 continue;
2423 }
2424 } else {
2425 array_push($onlineUsersData, $userData[$key]);
2426 }
2427 } else {
2428 array_push($onlineUsersData, $userData);
2429 }
2430 }
2431 return $onlineUsersData;
2432 }
2433
2434 return $this->_onlineUsersData;
2435 }
2436
2437 function removeUserFromOnlineUsersData($userID=null) {
2438 if(!$this->_onlineUsersData) {
2439 return;
2440 }
2441 $userID = ($userID === null) ? $this->getUserID() : $userID;
2442 for($i=0; $i<count($this->_onlineUsersData); $i++) {
2443 if($this->_onlineUsersData[$i]['userID'] == $userID) {
2444 array_splice($this->_onlineUsersData, $i, 1);
2445 break;
2446 }
2447 }
2448 }
2449
2450 function resetOnlineUsersData() {
2451 $this->_onlineUsersData = null;
2452 }
2453
2454 function getOnlineUsers($channelIDs=null) {
2455 return $this->getOnlineUsersData($channelIDs, 'userName');
2456 }
2457
2458 function getOnlineUserIDs($channelIDs=null) {
2459 return $this->getOnlineUsersData($channelIDs, 'userID');
2460 }
2461
2462 function startSession() {
2463 if(!session_id()) {
2464 // Set the session name:
2465 session_name($this->getConfig('sessionName'));
2466
2467 // Set session cookie parameters:
2468 session_set_cookie_params(
2469 0, // The session is destroyed on logout anyway, so no use to set this
2470 $this->getConfig('sessionCookiePath'),
2471 $this->getConfig('sessionCookieDomain'),
2472 $this->getConfig('sessionCookieSecure')
2473 );
2474
2475 // Start the session:
2476 session_start();
2477
2478 // We started a new session:
2479 $this->_sessionNew = true;
2480 }
2481 }
2482
2483 function destroySession() {
2484 if($this->_sessionNew) {
2485 // Delete all session variables:
2486 $_SESSION = array();
2487
2488 // Delete the session cookie:
2489 if (isset($_COOKIE[session_name()])) {
2490 setcookie(
2491 session_name(),
2492 '',
2493 time()-42000,
2494 $this->getConfig('sessionCookiePath'),
2495 $this->getConfig('sessionCookieDomain'),
2496 $this->getConfig('sessionCookieSecure')
2497 );
2498 }
2499
2500 // Destroy the session:
2501 session_destroy();
2502 } else {
2503 // Unset all session variables starting with the sessionKeyPrefix:
2504 foreach($_SESSION as $key=>$value) {
2505 if(strpos($key, $this->getConfig('sessionKeyPrefix')) === 0) {
2506 unset($_SESSION[$key]);
2507 }
2508 }
2509 }
2510 }
2511
2512 function regenerateSessionID() {
2513 if($this->_sessionNew) {
2514 // Regenerate session id:
2515 @session_regenerate_id(true);
2516 }
2517 }
2518
2519 function getSessionVar($key, $prefix=null) {
2520 if($prefix === null)
2521 $prefix = $this->getConfig('sessionKeyPrefix');
2522
2523 // Return the session value if existing:
2524 if(isset($_SESSION[$prefix.$key]))
2525 return $_SESSION[$prefix.$key];
2526 else
2527 return null;
2528 }
2529
2530 function setSessionVar($key, $value, $prefix=null) {
2531 if($prefix === null)
2532 $prefix = $this->getConfig('sessionKeyPrefix');
2533
2534 // Set the session value:
2535 $_SESSION[$prefix.$key] = $value;
2536 }
2537
2538 function getSessionIP() {
2539 return $this->getSessionVar('IP');
2540 }
2541
2542 function setSessionIP($ip) {
2543 $this->setSessionVar('IP', $ip);
2544 }
2545
2546 function getQueryUserName() {
2547 return $this->getSessionVar('QueryUserName');
2548 }
2549
2550 function setQueryUserName($userName) {
2551 $this->setSessionVar('QueryUserName', $userName);
2552 }
2553
2554 function getInvitations() {
2555 if($this->_invitations === null) {
2556 $this->_invitations = array();
2557
2558 $sql = 'SELECT
2559 channel
2560 FROM
2561 '.$this->getDataBaseTable('invitations').'
2562 WHERE
2563 userID='.$this->db->makeSafe($this->getUserID()).'
2564 AND
2565 DATE_SUB(NOW(), interval 1 DAY) < dateTime;';
2566
2567 // Create a new SQL query:
2568 $result = $this->db->sqlQuery($sql);
2569
2570 // Stop if an error occurs:
2571 if($result->error()) {
2572 echo $result->getError();
2573 die();
2574 }
2575
2576 while($row = $result->fetch()) {
2577 array_push($this->_invitations, $row['channel']);
2578 }
2579
2580 $result->free();
2581 }
2582 return $this->_invitations;
2583 }
2584
2585 function removeExpiredInvitations() {
2586 $sql = 'DELETE FROM
2587 '.$this->getDataBaseTable('invitations').'
2588 WHERE
2589 DATE_SUB(NOW(), interval 1 DAY) > dateTime;';
2590
2591 // Create a new SQL query:
2592 $result = $this->db->sqlQuery($sql);
2593
2594 // Stop if an error occurs:
2595 if($result->error()) {
2596 echo $result->getError();
2597 die();
2598 }
2599 }
2600
2601 function addInvitation($userID, $channelID=null) {
2602 $this->removeExpiredInvitations();
2603
2604 $channelID = ($channelID === null) ? $this->getChannel() : $channelID;
2605
2606 $sql = 'INSERT INTO '.$this->getDataBaseTable('invitations').'(
2607 userID,
2608 channel,
2609 dateTime
2610 )
2611 VALUES (
2612 '.$this->db->makeSafe($userID).',
2613 '.$this->db->makeSafe($channelID).',
2614 NOW()
2615 );';
2616
2617 // Create a new SQL query:
2618 $result = $this->db->sqlQuery($sql);
2619
2620 // Stop if an error occurs:
2621 if($result->error()) {
2622 echo $result->getError();
2623 die();
2624 }
2625 }
2626
2627 function removeInvitation($userID, $channelID=null) {
2628 $channelID = ($channelID === null) ? $this->getChannel() : $channelID;
2629
2630 $sql = 'DELETE FROM
2631 '.$this->getDataBaseTable('invitations').'
2632 WHERE
2633 userID='.$this->db->makeSafe($userID).'
2634 AND
2635 channel='.$this->db->makeSafe($channelID).';';
2636
2637 // Create a new SQL query:
2638 $result = $this->db->sqlQuery($sql);
2639
2640 // Stop if an error occurs:
2641 if($result->error()) {
2642 echo $result->getError();
2643 die();
2644 }
2645 }
2646
2647 function getUserID() {
2648 return $this->getSessionVar('UserID');
2649 }
2650
2651 function setUserID($id) {
2652 $this->setSessionVar('UserID', $id);
2653 }
2654
2655 function getUserName() {
2656 return $this->getSessionVar('UserName');
2657 }
2658
2659 function setUserName($name) {
2660 $this->setSessionVar('UserName', $name);
2661 }
2662
2663 function getLoginUserName() {
2664 return $this->getSessionVar('LoginUserName');
2665 }
2666
2667 function setLoginUserName($name) {
2668 $this->setSessionVar('LoginUserName', $name);
2669 }
2670
2671 function getUserRole() {
2672 $userRole = $this->getSessionVar('UserRole');
2673 if($userRole === null)
2674 return AJAX_CHAT_GUEST;
2675 return $userRole;
2676 }
2677
2678 function setUserRole($role) {
2679 $this->setSessionVar('UserRole', $role);
2680 }
2681
2682 function getChannel() {
2683 return $this->getSessionVar('Channel');
2684 }
2685
2686 function setChannel($channel) {
2687 $this->setSessionVar('Channel', $channel);
2688
2689 // Save the channel enter timestamp:
2690 $this->setChannelEnterTimeStamp(time());
2691
2692 // Update the channel authentication for the socket server:
2693 if($this->getConfig('socketServerEnabled')) {
2694 $this->updateSocketAuthentication(
2695 $this->getUserID(),
2696 $this->getSocketRegistrationID(),
2697 array($channel,$this->getPrivateMessageID())
2698 );
2699 }
2700
2701 // Reset the logs view socket authentication session var:
2702 if($this->getSessionVar('logsViewSocketAuthenticated')) {
2703 $this->setSessionVar('logsViewSocketAuthenticated', false);
2704 }
2705 }
2706
2707 function isLoggedIn() {
2708 return (bool)$this->getSessionVar('LoggedIn');
2709 }
2710
2711 function setLoggedIn($bool) {
2712 $this->setSessionVar('LoggedIn', $bool);
2713 }
2714
2715 function getLoginTimeStamp() {
2716 return $this->getSessionVar('LoginTimeStamp');
2717 }
2718
2719 function setLoginTimeStamp($time) {
2720 $this->setSessionVar('LoginTimeStamp', $time);
2721 }
2722
2723 function getChannelEnterTimeStamp() {
2724 return $this->getSessionVar('ChannelEnterTimeStamp');
2725 }
2726
2727 function setChannelEnterTimeStamp($time) {
2728 $this->setSessionVar('ChannelEnterTimeStamp', $time);
2729 }
2730
2731 function getStatusUpdateTimeStamp() {
2732 return $this->getSessionVar('StatusUpdateTimeStamp');
2733 }
2734
2735 function setStatusUpdateTimeStamp($time) {
2736 $this->setSessionVar('StatusUpdateTimeStamp', $time);
2737 }
2738
2739 function getInactiveCheckTimeStamp() {
2740 return $this->getSessionVar('InactiveCheckTimeStamp');
2741 }
2742
2743 function setInactiveCheckTimeStamp($time) {
2744 $this->setSessionVar('InactiveCheckTimeStamp', $time);
2745 }
2746
2747 function getInsertedMessagesRate() {
2748 return $this->getSessionVar('InsertedMessagesRate');
2749 }
2750
2751 function setInsertedMessagesRate($rate) {
2752 $this->setSessionVar('InsertedMessagesRate', $rate);
2753 }
2754
2755 function getInsertedMessagesRateTimeStamp() {
2756 return $this->getSessionVar('InsertedMessagesRateTimeStamp');
2757 }
2758
2759 function setInsertedMessagesRateTimeStamp($time) {
2760 $this->setSessionVar('InsertedMessagesRateTimeStamp', $time);
2761 }
2762
2763 function getLangCode() {
2764 // Get the langCode from request or cookie:
2765 $langCodeCookie = isset($_COOKIE[$this->getConfig('sessionName').'_lang']) ? $_COOKIE[$this->getConfig('sessionName').'_lang'] : null;
2766 $langCode = $this->getRequestVar('lang') ? $this->getRequestVar('lang') : $langCodeCookie;
2767 // Check if the langCode is valid:
2768 if(!in_array($langCode, $this->getConfig('langAvailable'))) {
2769 // Determine the user language:
2770 $language = new AJAXChatLanguage($this->getConfig('langAvailable'), $this->getConfig('langDefault'));
2771 $langCode = $language->getLangCode();
2772 }
2773 return $langCode;
2774 }
2775
2776 function setLangCodeCookie() {
2777 setcookie(
2778 $this->getConfig('sessionName').'_lang',
2779 $this->getLangCode(),
2780 time()+60*60*24*$this->getConfig('sessionCookieLifeTime'),
2781 $this->getConfig('sessionCookiePath'),
2782 $this->getConfig('sessionCookieDomain'),
2783 $this->getConfig('sessionCookieSecure')
2784 );
2785 }
2786
2787 function removeUnsafeCharacters($str) {
2788 // Remove NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127:
2789 return AJAXChatEncoding::removeUnsafeCharacters($str);
2790 }
2791
2792 function subString($str, $start=0, $length=null, $encoding='UTF-8') {
2793 return AJAXChatString::subString($str, $start, $length, $encoding);
2794 }
2795
2796 function stringLength($str, $encoding='UTF-8') {
2797 return AJAXChatString::stringLength($str, $encoding);
2798 }
2799
2800 function trimMessageText($text) {
2801 return $this->trimString($text, 'UTF-8', $this->getConfig('messageTextMaxLength'));
2802 }
2803
2804 function trimUserName($userName) {
2805 return $this->trimString($userName, null, $this->getConfig('userNameMaxLength'), true, true);
2806 }
2807
2808 function trimChannelName($channelName) {
2809 return $this->trimString($channelName, null, null, true, true);
2810 }
2811
2812 function trimString($str, $sourceEncoding=null, $maxLength=null, $replaceWhitespace=false, $decodeEntities=false, $htmlEntitiesMap=null) {
2813 // Make sure the string contains valid unicode:
2814 $str = $this->convertToUnicode($str, $sourceEncoding);
2815
2816 // Make sure the string contains no unsafe characters:
2817 $str = $this->removeUnsafeCharacters($str);
2818
2819 // Strip whitespace from the beginning and end of the string:
2820 $str = trim($str);
2821
2822 if($replaceWhitespace) {
2823 // Replace any whitespace in the userName with the underscore "_":
2824 $str = preg_replace('/\s/u', '_', $str);
2825 }
2826
2827 if($decodeEntities) {
2828 // Decode entities:
2829 $str = $this->decodeEntities($str, 'UTF-8', $htmlEntitiesMap);
2830 }
2831
2832 if($maxLength) {
2833 // Cut the string to the allowed length:
2834 $str = $this->subString($str, 0, $maxLength);
2835 }
2836
2837 return $str;
2838 }
2839
2840 function convertToUnicode($str, $sourceEncoding=null) {
2841 if($sourceEncoding === null) {
2842 $sourceEncoding = $this->getConfig('sourceEncoding');
2843 }
2844 return $this->convertEncoding($str, $sourceEncoding, 'UTF-8');
2845 }
2846
2847 function convertFromUnicode($str, $contentEncoding=null) {
2848 if($contentEncoding === null) {
2849 $contentEncoding = $this->getConfig('contentEncoding');
2850 }
2851 return $this->convertEncoding($str, 'UTF-8', $contentEncoding);
2852 }
2853
2854 function convertEncoding($str, $charsetFrom, $charsetTo) {
2855 return AJAXChatEncoding::convertEncoding($str, $charsetFrom, $charsetTo);
2856 }
2857
2858 function encodeEntities($str, $encoding='UTF-8', $convmap=null) {
2859 return AJAXChatEncoding::encodeEntities($str, $encoding, $convmap);
2860 }
2861
2862 function decodeEntities($str, $encoding='UTF-8', $htmlEntitiesMap=null) {
2863 return AJAXChatEncoding::decodeEntities($str, $encoding, $htmlEntitiesMap);
2864 }
2865
2866 function htmlEncode($str) {
2867 return AJAXChatEncoding::htmlEncode($str, $this->getConfig('contentEncoding'));
2868 }
2869
2870 function encodeSpecialChars($str) {
2871 return AJAXChatEncoding::encodeSpecialChars($str);
2872 }
2873
2874 function decodeSpecialChars($str) {
2875 return AJAXChatEncoding::decodeSpecialChars($str);
2876 }
2877
2878 function ipToStorageFormat($ip) {
2879 if(function_exists('inet_pton')) {
2880 // ipv4 & ipv6:
2881 return @inet_pton($ip);
2882 }
2883 // Only ipv4:
2884 return @pack('N',@ip2long($ip));
2885 }
2886
2887 function ipFromStorageFormat($ip) {
2888 if(function_exists('inet_ntop')) {
2889 // ipv4 & ipv6:
2890 return @inet_ntop($ip);
2891 }
2892 // Only ipv4:
2893 $unpacked = @unpack('Nlong',$ip);
2894 if(isset($unpacked['long'])) {
2895 return @long2ip($unpacked['long']);
2896 }
2897 return null;
2898 }
2899
2900 function getConfig($key, $subkey=null) {
2901 if($subkey)
2902 return $this->_config[$key][$subkey];
2903 else
2904 return $this->_config[$key];
2905 }
2906
2907 function setConfig($key, $subkey, $value) {
2908 if($subkey) {
2909 if(!isset($this->_config[$key])) {
2910 $this->_config[$key] = array();
2911 }
2912 $this->_config[$key][$subkey] = $value;
2913 } else {
2914 $this->_config[$key] = $value;
2915 }
2916 }
2917
2918 function getLang($key=null) {
2919 if(!$this->_lang) {
2920 // Include the language file:
2921 $lang = null;
2922 require(AJAX_CHAT_PATH.'lib/lang/'.$this->getLangCode().'.php');
2923 $this->_lang = &$lang;
2924 }
2925 if($key === null)
2926 return $this->_lang;
2927 if(isset($this->_lang[$key]))
2928 return $this->_lang[$key];
2929 return null;
2930 }
2931
2932 function getChatURL() {
2933 if(defined('AJAX_CHAT_URL')) {
2934 return AJAX_CHAT_URL;
2935 }
2936
2937 return
2938 (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').
2939 (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
2940 (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
2941 (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] == 443 || $_SERVER['SERVER_PORT'] == 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
2942 substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')+1);
2943 }
2944
2945 function getIDFromName($userName) {
2946 $userDataArray = $this->getOnlineUsersData(null,'userName',$userName);
2947 if($userDataArray && isset($userDataArray[0])) {
2948 return $userDataArray[0]['userID'];
2949 }
2950 return null;
2951 }
2952
2953 function getNameFromID($userID) {
2954 $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
2955 if($userDataArray && isset($userDataArray[0])) {
2956 return $userDataArray[0]['userName'];
2957 }
2958 return null;
2959 }
2960
2961 function getChannelFromID($userID) {
2962 $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
2963 if($userDataArray && isset($userDataArray[0])) {
2964 return $userDataArray[0]['channel'];
2965 }
2966 return null;
2967 }
2968
2969 function getIPFromID($userID) {
2970 $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
2971 if($userDataArray && isset($userDataArray[0])) {
2972 return $userDataArray[0]['ip'];
2973 }
2974 return null;
2975 }
2976
2977 function getRoleFromID($userID) {
2978 $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
2979 if($userDataArray && isset($userDataArray[0])) {
2980 return $userDataArray[0]['userRole'];
2981 }
2982 return null;
2983 }
2984
2985 function getChannelNames() {
2986 return array_flip($this->getChannels());
2987 }
2988
2989 function getChannelIDFromChannelName($channelName) {
2990 if(!$channelName)
2991 return null;
2992 $channels = $this->getAllChannels();
2993 if(array_key_exists($channelName,$channels)) {
2994 return $channels[$channelName];
2995 }
2996 $channelID = null;
2997 // Check if the requested channel is the own private channel:
2998 if($channelName == $this->getPrivateChannelName()) {
2999 return $this->getPrivateChannelID();
3000 }
3001 // Try to retrieve a private room ID:
3002 $strlenChannelName = $this->stringLength($channelName);
3003 $strlenPrefix = $this->stringLength($this->getConfig('privateChannelPrefix'));
3004 $strlenSuffix = $this->stringLength($this->getConfig('privateChannelSuffix'));
3005 if($this->subString($channelName,0,$strlenPrefix) == $this->getConfig('privateChannelPrefix')
3006 && $this->subString($channelName,$strlenChannelName-$strlenSuffix) == $this->getConfig('privateChannelSuffix')) {
3007 $userName = $this->subString(
3008 $channelName,
3009 $strlenPrefix,
3010 $strlenChannelName-($strlenPrefix+$strlenSuffix)
3011 );
3012 $userID = $this->getIDFromName($userName);
3013 if($userID !== null) {
3014 $channelID = $this->getPrivateChannelID($userID);
3015 }
3016 }
3017 return $channelID;
3018 }
3019
3020 function getChannelNameFromChannelID($channelID) {
3021 foreach($this->getAllChannels() as $key=>$value) {
3022 if($value == $channelID) {
3023 return $key;
3024 }
3025 }
3026 // Try to retrieve a private room name:
3027 if($channelID == $this->getPrivateChannelID()) {
3028 return $this->getPrivateChannelName();
3029 }
3030 $userName = $this->getNameFromID($channelID-$this->getConfig('privateChannelDiff'));
3031 if($userName === null) {
3032 return null;
3033 }
3034 return $this->getPrivateChannelName($userName);
3035 }
3036
3037 function getChannelName() {
3038 return $this->getChannelNameFromChannelID($this->getChannel());
3039 }
3040
3041 function getPrivateChannelName($userName=null) {
3042 if($userName === null) {
3043 $userName = $this->getUserName();
3044 }
3045 return $this->getConfig('privateChannelPrefix').$userName.$this->getConfig('privateChannelSuffix');
3046 }
3047
3048 function getPrivateChannelID($userID=null) {
3049 if($userID === null) {
3050 $userID = $this->getUserID();
3051 }
3052 return $userID + $this->getConfig('privateChannelDiff');
3053 }
3054
3055 function getPrivateMessageID($userID=null) {
3056 if($userID === null) {
3057 $userID = $this->getUserID();
3058 }
3059 return $userID + $this->getConfig('privateMessageDiff');
3060 }
3061
3062 function isAllowedToSendPrivateMessage() {
3063 if($this->getConfig('allowPrivateMessages') || $this->getUserRole() == AJAX_CHAT_ADMIN) {
3064 return true;
3065 }
3066 return false;
3067 }
3068
3069 function isAllowedToCreatePrivateChannel() {
3070 if($this->getConfig('allowPrivateChannels')) {
3071 switch($this->getUserRole()) {
3072 case AJAX_CHAT_USER:
3073 return true;
3074 case AJAX_CHAT_MODERATOR:
3075 return true;
3076 case AJAX_CHAT_ADMIN:
3077 return true;
3078 default:
3079 return false;
3080 }
3081 }
3082 return false;
3083 }
3084
3085 function isAllowedToListHiddenUsers() {
3086 // Hidden users are users within private or restricted channels:
3087 switch($this->getUserRole()) {
3088 case AJAX_CHAT_MODERATOR:
3089 return true;
3090 case AJAX_CHAT_ADMIN:
3091 return true;
3092 default:
3093 return false;
3094 }
3095 }
3096
3097 function isUserOnline($userID=null) {
3098 $userID = ($userID === null) ? $this->getUserID() : $userID;
3099 $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
3100 if($userDataArray && count($userDataArray) > 0) {
3101 return true;
3102 }
3103 return false;
3104 }
3105
3106 function isUserNameInUse($userName=null) {
3107 $userName = ($userName === null) ? $this->getUserName() : $userName;
3108 $userDataArray = $this->getOnlineUsersData(null,'userName',$userName);
3109 if($userDataArray && count($userDataArray) > 0) {
3110 return true;
3111 }
3112 return false;
3113 }
3114
3115 function isUserBanned($userName, $userID=null, $ip=null) {
3116 if($userID !== null) {
3117 $bannedUserDataArray = $this->getBannedUsersData('userID',$userID);
3118 if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
3119 return true;
3120 }
3121 }
3122 if($ip !== null) {
3123 $bannedUserDataArray = $this->getBannedUsersData('ip',$ip);
3124 if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
3125 return true;
3126 }
3127 }
3128 $bannedUserDataArray = $this->getBannedUsersData('userName',$userName);
3129 if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
3130 return true;
3131 }
3132 return false;
3133 }
3134
3135 function isMaxUsersLoggedIn() {
3136 if(count($this->getOnlineUsersData()) >= $this->getConfig('maxUsersLoggedIn')) {
3137 return true;
3138 }
3139 return false;
3140 }
3141
3142 function validateChannel($channelID) {
3143 if($channelID === null) {
3144 return false;
3145 }
3146 // Return true for normal channels the user has acces to:
3147 if(in_array($channelID, $this->getChannels())) {
3148 return true;
3149 }
3150 // Return true if the user is allowed to join his own private channel:
3151 if($channelID == $this->getPrivateChannelID() && $this->isAllowedToCreatePrivateChannel()) {
3152 return true;
3153 }
3154 // Return true if the user has been invited to a restricted or private channel:
3155 if(in_array($channelID, $this->getInvitations())) {
3156 return true;
3157 }
3158 // No valid channel, return false:
3159 return false;
3160 }
3161
3162 function createGuestUserName() {
3163 $maxLength = $this->getConfig('userNameMaxLength')
3164 - $this->stringLength($this->getConfig('guestUserPrefix'))
3165 - $this->stringLength($this->getConfig('guestUserSuffix'));
3166require_once 'vkapi.class.php'; #путь к файлу vkapi.class.php
3167 $api_id = '5877981'; #id приложениÑ
3168 $secret_key = 'yFFMjEUS1MXMCLKBitFz'; #Ñекретный ключ приложениÑ
3169$viewer_id = $_GET['viewer_id']; // id пользователÑ,не знаю откуда брать будешь
3170$VK = new vkapi($api_id, $secret_key);
3171$respo = $VK->api('getProfiles', array('uids'=>$viewer_id,'fields'=>'photo_50,first_name,last_name,sex'));
3172$id = $respo['response'][0]['uid'];
3173$fot = $respo['response'][0]['photo_50']; // Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñ ÑÑылкой
3174$name = $respo['response'][0]['first_name'];
3175$fam = $respo['response'][0]['last_name'];
3176//Ð¥ÑƒÐ¹Ð½Ñ Ñ Ð²Ð½Ð¾Ñом ID в базу
3177 $db_host = 'localhost'; // Ð°Ð´Ñ€ÐµÑ Ñервера
3178 $db_name = 'wm16684_wchat'; // Ð¸Ð¼Ñ Ð±Ð°Ð·Ñ‹ данных
3179 $db_user = 'wm16684_wchat'; // Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ
3180 $db_password = 'wchat'; // пароль
3181 $db = mysql_connect($db_host,$db_user,$db_password) OR DIE("Ðе могу Ñоздать Ñоединение ");
3182 mysql_select_db("wm16684_wchat",$db);
3183
3184 // УÑтановка кодировки ÑоединениÑ
3185 mysql_query("SET NAMES 'utf8'",$db);
3186 $result = mysql_query ("INSERT INTO users (uid) VALUES ('$uid')");
3187 //Закончили хуйню
3188 // seed with microseconds since last "whole" second:
3189 mt_srand((double)microtime()*1000000);
3190
3191 // Create a random userName using numbers between 100000 and 999999:
3192
3193 $userName = $respo['response'][0]['first_name']; //substr(mt_rand(100000, 999999), 0, $maxLength);
3194
3195 return $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix');
3196 }
3197
3198 // Guest userIDs must not interfere with existing userIDs and must be lower than privateChannelDiff:
3199 function createGuestUserID() {
3200 // seed with microseconds since last "whole" second:
3201 mt_srand((double)microtime()*1000000);
3202
3203 return mt_rand($this->getConfig('minGuestUserID'), $this->getConfig('privateChannelDiff')-1);
3204 }
3205
3206 function getGuestUser() {
3207 if(!$this->getConfig('allowGuestLogins'))
3208 return null;
3209
3210 if($this->getConfig('allowGuestUserName')) {
3211 $maxLength = $this->getConfig('userNameMaxLength')
3212 - $this->stringLength($this->getConfig('guestUserPrefix'))
3213 - $this->stringLength($this->getConfig('guestUserSuffix'));
3214
3215 // Trim guest userName:
3216 $userName = $this->trimString($this->getRequestVar('userName'), null, $maxLength, true, true);
3217
3218 // If given userName is invalid, create one:
3219 if(!$userName) {
3220 $userName = $this->createGuestUserName();
3221 } else {
3222 // Add the guest users prefix and suffix to the given userName:
3223 $userName = $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix');
3224 }
3225 } else {
3226 $userName = $this->createGuestUserName();
3227 }
3228
3229 $userData = array();
3230 $userData['userID'] = $this->createGuestUserID();
3231 $userData['userName'] = $userName;
3232 $userData['userRole'] = AJAX_CHAT_GUEST;
3233 return $userData;
3234 }
3235
3236 function getCustomVar($key) {
3237 if(!isset($this->_customVars))
3238 $this->_customVars = array();
3239 if(!isset($this->_customVars[$key]))
3240 return null;
3241 return $this->_customVars[$key];
3242 }
3243
3244 function setCustomVar($key, $value) {
3245 if(!isset($this->_customVars))
3246 $this->_customVars = array();
3247 $this->_customVars[$key] = $value;
3248 }
3249
3250 // Override to replace custom template tags:
3251 // Return the replacement for the given tag (and given tagContent)
3252 function replaceCustomTemplateTags($tag, $tagContent) {
3253 return null;
3254 }
3255
3256 // Override to initialize custom configuration settings:
3257 function initCustomConfig() {
3258 }
3259
3260 // Override to add custom request variables:
3261 // Add values to the request variables array: $this->_requestVars['customVariable'] = null;
3262 function initCustomRequestVars() {
3263 }
3264
3265 // Override to add custom session code right after the session has been started:
3266 function initCustomSession() {
3267 }
3268
3269 // Override, to parse custom info requests:
3270 // $infoRequest contains the current info request
3271 // Add info responses using the method addInfoMessage($info, $type)
3272 function parseCustomInfoRequest($infoRequest) {
3273 }
3274
3275 // Override to replace custom text:
3276 // Return replaced text
3277 // $text contains the whole message
3278 function replaceCustomText(&$text) {
3279 return $text;
3280 }
3281
3282 // Override to add custom commands:
3283 // Return true if a custom command has been successfully parsed, else false
3284 // $text contains the whole message, $textParts the message split up as words array
3285 function parseCustomCommands($text, $textParts) {
3286 return false;
3287 }
3288
3289 // Override to perform custom actions on new messages:
3290 // Return true if message may be inserted, else false
3291 // $text contains the whole message
3292 function onNewMessage($text) {
3293 return true;
3294 }
3295
3296 // Override to perform custom actions on new messages:
3297 // Method to set the style cookie depending on user data
3298 function setStyle() {
3299 }
3300
3301 // Override:
3302 // Returns true if the userID of the logged in user is identical to the userID of the authentication system
3303 // or the user is authenticated as guest in the chat and the authentication system
3304 function revalidateUserID() {
3305 return true;
3306 }
3307
3308 // Override:
3309 // Returns an associative array containing userName, userID and userRole
3310 // Returns null if login is invalid
3311 function getValidLoginUserData() {
3312 // Check if we have a valid registered user:
3313 if(false) {
3314 // Here is the place to check user authentication
3315 } else {
3316 // Guest users:
3317 return $this->getGuestUser();
3318 }
3319 }
3320
3321 // Override:
3322 // Store the channels the current user has access to
3323 // Make sure channel names don't contain any whitespace
3324 function &getChannels() {
3325 if($this->_channels === null) {
3326 $this->_channels = $this->getAllChannels();
3327 }
3328 return $this->_channels;
3329 }
3330
3331 // Override:
3332 // Store all existing channels
3333 // Make sure channel names don't contain any whitespace
3334 function &getAllChannels() {
3335 if($this->_allChannels === null) {
3336 $this->_allChannels = array();
3337
3338 // Default channel, public to everyone:
3339 $this->_allChannels[$this->trimChannelName($this->getConfig('defaultChannelName'))] = $this->getConfig('defaultChannelID');
3340 }
3341 return $this->_allChannels;
3342 }
3343
3344}
3345?>