/** * Returns rendered channel statistics. * * @param WiseChatChannel $channel * * @return string HTML source */ public function getRenderedChannelStats($channel) { if ($channel === null) { return 'ERROR: channel does not exist'; } $variables = array('channel' => $channel->getName(), 'messages' => $this->messagesService->getNumberByChannelName($channel->getName()), 'users' => $this->channelUsersDAO->getAmountOfUsersInChannel($channel->getId())); return $this->getTemplatedString($variables, $this->options->getOption('template', 'ERROR: TEMPLATE NOT SPECIFIED')); }
/** * Determines whether current user has given right. * * @param string $rightName * * @return boolean */ public function hasCurrentWpUserRight($rightName) { $wpUser = $this->getCurrentWpUser(); if ($wpUser !== null) { $targetRole = $this->options->getOption("permission_{$rightName}_role", 'administrator'); if (is_array($wpUser->roles) && in_array($targetRole, $wpUser->roles) || current_user_can("wise_chat_{$rightName}")) { return true; } } return false; }
/** * Returns all filters * * @param boolean $htmlEscape * * @return array */ public function getAll($htmlEscape = false) { $filters = $this->options->getOption('filters', array()); if (!is_array($filters)) { return array(); } $filtersOut = array(); foreach ($filters as $key => $filter) { $type = $filter['type']; $replace = $filter['replace']; $with = $filter['with']; $label = $this->types[$type] . (in_array($type, array('text', 'regexp')) ? ': ' . $replace : ''); if ($htmlEscape) { $replace = htmlentities($replace, ENT_QUOTES, 'UTF-8'); $with = htmlentities($with, ENT_QUOTES, 'UTF-8'); $label = htmlentities($label, ENT_QUOTES, 'UTF-8'); } $filtersOut[] = array('id' => $key, 'replace' => $replace, 'with' => $with, 'label' => $label, 'type' => $type); } return $filtersOut; }
/** * Adds single length style definition. * * @param string $cssSelector * @param string $lengthProperty * @param string $cssProperty * * @return null */ private function addLengthDefinition($cssSelector, $lengthProperty, $cssProperty) { if ($this->options->isOptionNotEmpty($lengthProperty)) { $value = $this->options->getOption($lengthProperty); if (preg_match('/^\\d+$/', $value)) { $value .= 'px'; } if (preg_match('/^\\d+((px)|%)$/', $value)) { $this->addRawDefinition($cssSelector, $cssProperty, $value); } } }
/** * Callback method for displaying list of checkboxes with a hint. * * @param array $args Array containing keys: id, name, hint, options * * @return null */ public function checkboxesCallback($args) { $id = $args['id']; $hint = $args['hint']; $options = $args['options']; $defaults = $this->getDefaultValues(); $defaultValue = array_key_exists($id, $defaults) ? $defaults[$id] : ''; $values = $this->options->getOption($id, $defaultValue); $parentId = $this->getFieldParent($id); $html = ''; foreach ($options as $key => $value) { $html .= sprintf('<label><input type="checkbox" value="%s" name="%s[%s][]" %s %s data-parent-field="%s" />%s</label> ', $key, WiseChatOptions::OPTIONS_NAME, $id, in_array($value, $values) ? 'checked="1"' : '', $parentId != null && !$this->options->isOptionEnabled($parentId, false) ? 'disabled="1"' : '', $parentId != null ? $parentId : '', $value); } printf($html); if (strlen($hint) > 0) { printf('<p class="description">%s</p>', $hint); } }
/** * Determines whether the chat is open according to the settings. * * @return boolean */ public function isChatOpen() { if ($this->options->isOptionEnabled('enable_opening_control', false)) { $chatOpeningDays = $this->options->getOption('opening_days'); if (is_array($chatOpeningDays) && !in_array(date('l'), $chatOpeningDays)) { return false; } $chatOpeningHours = $this->options->getOption('opening_hours'); $openingHour = $chatOpeningHours['opening']; $openingMode = $chatOpeningHours['openingMode']; $startHourDate = null; if ($openingMode != '24h') { $startHourDate = DateTime::createFromFormat('Y-m-d h:i a', date('Y-m-d') . ' ' . $openingHour . ' ' . $openingMode); } else { $startHourDate = DateTime::createFromFormat('Y-m-d H:i', date('Y-m-d') . ' ' . $openingHour); } $closingHour = $chatOpeningHours['closing']; $closingMode = $chatOpeningHours['closingMode']; $endHourDate = null; if ($closingMode != '24h') { $endHourDate = DateTime::createFromFormat('Y-m-d h:i a', date('Y-m-d') . ' ' . $closingHour . ' ' . $closingMode); } else { $endHourDate = DateTime::createFromFormat('Y-m-d H:i', date('Y-m-d') . ' ' . $closingHour); } if ($startHourDate != null && $endHourDate != null) { $nowDate = new DateTime(); $nowU = $nowDate->format('U'); $startHourDateU = $startHourDate->format('U'); $endHourDateU = $endHourDate->format('U'); if ($startHourDateU <= $endHourDateU) { if ($nowU < $startHourDateU || $nowU > $endHourDateU) { return false; } } else { if ($nowU > $endHourDateU && $nowU < $startHourDateU) { return false; } } } } return true; }
/** * Validates given username. * * @param string $userName * * @return string Validated username (trimmed and filtered) * @throws Exception If username is not valid */ public function validateUserName($userName) { $userName = trim($userName); // check for valid characters: if (strlen($userName) == 0 || !preg_match('/^[a-zA-Z0-9\\-_ ]+$/', $userName)) { throw new Exception($this->options->getOption('message_error_1', 'Only letters, number, spaces, hyphens and underscores are allowed')); } // filter the new username: if ($this->options->isOptionEnabled('filter_bad_words')) { WiseChatContainer::load('rendering/filters/pre/WiseChatFilter'); $userName = WiseChatFilter::filter($userName); } // check if the new username is already occupied: $occupiedException = new Exception($this->options->getOption('message_error_2', 'This name is already occupied')); $prefix = $this->options->getOption('user_name_prefix', 'Anonymous'); if ($this->getUserNameOrEmptyString() == $userName || $this->usersDAO->getWpUserByDisplayName($userName) !== null || $this->usersDAO->getWpUserByLogin($userName) !== null || $this->channelUsersDAO->isUserNameOccupied($userName, $this->userSessionDAO->getSessionId()) || preg_match("/^{$prefix}/", $userName) || $userName == $this->getSystemUser()->getName()) { throw $occupiedException; } return $userName; }
/** * Returns chat HTML for given channel. * * @param string|null $channelName * * @return string * @throws Exception */ public function getRenderedChat($channelName = null) { $channel = $this->service->createAndGetChannel($this->service->getValidChatChannelName($channelName)); if ($this->service->isChatRestrictedForAnonymousUsers()) { return $this->renderer->getRenderedAccessDenied($this->options->getOption('message_error_4', 'Only logged in users are allowed to enter the chat'), 'wcAccessDenied'); } if (!$this->service->isChatOpen()) { return $this->renderer->getRenderedAccessDenied($this->options->getOption('message_error_5', 'The chat is closed now'), 'wcChatClosed'); } if ($this->service->isChatChannelFull($channel)) { return $this->renderer->getRenderedAccessDenied($this->options->getOption('message_error_6', 'The chat is full now. Try again later.'), 'wcChatFull'); } if ($this->service->isChatChannelsLimitReached($channel)) { return $this->renderer->getRenderedAccessDenied($this->options->getOption('message_error_10', 'You cannot enter the chat due to the limit of channels you can participate simultaneously.'), 'wcChatChannelLimitFull'); } if ($this->service->hasUserToBeForcedToEnterName()) { if ($this->getPostParam('wcUserNameSelection') !== null) { try { $this->authentication->authenticate($this->getPostParam('wcUserName')); } catch (Exception $e) { return $this->renderer->getRenderedUserNameForm($e->getMessage()); } } else { return $this->renderer->getRenderedUserNameForm(); } } if ($this->service->hasUserToBeAuthorizedInChannel($channel)) { if ($this->getPostParam('wcChannelAuthorization') !== null) { if (!$this->service->authorize($channel, $this->getPostParam('wcChannelPassword'))) { return $this->renderer->getRenderedPasswordAuthorization($this->options->getOption('message_error_9', 'Invalid password.')); } } else { return $this->renderer->getRenderedPasswordAuthorization(); } } $chatId = $this->service->getChatID(); $this->userService->startUpMaintenance($channel); $this->bansService->startUpMaintenance(); $this->messagesService->startUpMaintenance($channel); $messages = $this->messagesService->getAllByChannelNameAndOffset($channel->getName()); $renderedMessages = ''; $lastId = 0; foreach ($messages as $message) { // omit non-admin messages: if ($message->isAdmin() && !$this->usersDAO->isWpUserAdminLogged()) { continue; } $renderedMessages .= $this->renderer->getRenderedMessage($message); if ($lastId < $message->getId()) { $lastId = $message->getId(); } } $lastAction = $this->actionsDAO->getLast(); $jsOptions = array('chatId' => $chatId, 'channelId' => $channel->getId(), 'nowTime' => gmdate('c', time()), 'lastId' => $lastId, 'checksum' => $this->getCheckSum(), 'lastActionId' => $lastAction !== null ? $lastAction->getId() : 0, 'baseDir' => $this->options->getBaseDir(), 'emoticonsBaseURL' => $this->options->getEmoticonsBaseURL(), 'apiEndpointBase' => $this->getEndpointBase(), 'messagesRefreshTime' => intval($this->options->getEncodedOption('messages_refresh_time', 3000)), 'messagesOrder' => $this->options->getEncodedOption('messages_order', '') == 'descending' ? 'descending' : 'ascending', 'enableTitleNotifications' => $this->options->isOptionEnabled('enable_title_notifications'), 'soundNotification' => $this->options->getEncodedOption('sound_notification'), 'messagesTimeMode' => $this->options->getEncodedOption('messages_time_mode'), 'channelUsersLimit' => $this->options->getIntegerOption('channel_users_limit', 0), 'messages' => array('message_sending' => $this->options->getEncodedOption('message_sending', 'Sending ...'), 'hint_message' => $this->options->getEncodedOption('hint_message'), 'messageSecAgo' => $this->options->getEncodedOption('message_sec_ago', 'sec. ago'), 'messageMinAgo' => $this->options->getEncodedOption('message_min_ago', 'min. ago'), 'messageYesterday' => $this->options->getEncodedOption('message_yesterday', 'yesterday'), 'messageUnsupportedTypeOfFile' => $this->options->getEncodedOption('message_error_7', 'Unsupported type of file.'), 'messageSizeLimitError' => $this->options->getEncodedOption('message_error_8', 'The size of the file exceeds allowed limit.')), 'userSettings' => $this->userSettingsDAO->getAll(), 'attachmentsValidFileFormats' => $this->attachmentsService->getAllowedFormats(), 'attachmentsSizeLimit' => $this->attachmentsService->getSizeLimit(), 'imagesSizeLimit' => $this->options->getIntegerOption('images_size_limit', 3145728)); $templater = new WiseChatTemplater($this->options->getPluginBaseDir()); $templater->setTemplateFile(WiseChatThemes::getInstance()->getMainTemplate()); $data = array('chatId' => $chatId, 'baseDir' => $this->options->getBaseDir(), 'messages' => $renderedMessages, 'themeStyles' => $this->options->getBaseDir() . WiseChatThemes::getInstance()->getCss(), 'showMessageSubmitButton' => $this->options->isOptionEnabled('show_message_submit_button'), 'showEmoticonInsertButton' => $this->options->isOptionEnabled('show_emoticon_insert_button', true), 'messageSubmitButtonCaption' => $this->options->getEncodedOption('message_submit_button_caption', 'Send'), 'showUsersList' => $this->options->isOptionEnabled('show_users'), 'usersList' => $this->options->isOptionEnabled('show_users') ? $this->renderer->getRenderedUsersList($channel) : '', 'showUsersCounter' => $this->options->isOptionEnabled('show_users_counter'), 'channelUsersLimit' => $this->options->getIntegerOption('channel_users_limit', 0), 'totalUsers' => $this->channelUsersDAO->getAmountOfUsersInChannel($channel->getId()), 'showUserName' => $this->options->isOptionEnabled('show_user_name'), 'currentUserName' => htmlentities($this->authentication->getUserNameOrEmptyString(), ENT_QUOTES, 'UTF-8'), 'isCurrentUserNameNotEmpty' => $this->authentication->isAuthenticated(), 'inputControlsTopLocation' => $this->options->getEncodedOption('input_controls_location') == 'top', 'inputControlsBottomLocation' => $this->options->getEncodedOption('input_controls_location') == '', 'showCustomizationsPanel' => $this->options->isOptionEnabled('allow_change_user_name') && !$this->usersDAO->isWpUserLogged() || $this->options->isOptionEnabled('allow_mute_sound') && strlen($this->options->getEncodedOption('sound_notification')) > 0 || $this->options->isOptionEnabled('allow_change_text_color'), 'allowChangeUserName' => $this->options->isOptionEnabled('allow_change_user_name') && !$this->usersDAO->isWpUserLogged(), 'allowMuteSound' => $this->options->isOptionEnabled('allow_mute_sound') && strlen($this->options->getEncodedOption('sound_notification')) > 0, 'allowChangeTextColor' => $this->options->isOptionEnabled('allow_change_text_color'), 'allowToSendMessages' => !$this->options->isOptionEnabled('read_only_for_anonymous', false) || $this->usersDAO->isWpUserLogged(), 'messageCustomize' => $this->options->getEncodedOption('message_customize', 'Customize'), 'messageName' => $this->options->getEncodedOption('message_name', 'Name'), 'messageSave' => $this->options->getEncodedOption('message_save', 'Save'), 'messageReset' => $this->options->getEncodedOption('message_reset', 'Reset'), 'messageMuteSounds' => $this->options->getEncodedOption('message_mute_sounds', 'Mute sounds'), 'messageTextColor' => $this->options->getEncodedOption('message_text_color', 'Text color'), 'messageTotalUsers' => $this->options->getEncodedOption('message_total_users', 'Total users'), 'messagePictureUploadHint' => $this->options->getEncodedOption('message_picture_upload_hint', 'Upload a picture'), 'messageAttachFileHint' => $this->options->getEncodedOption('message_attach_file_hint', 'Attach a file'), 'messageInsertEmoticon' => $this->options->getEncodedOption('message_insert_emoticon', 'Insert an emoticon'), 'windowTitle' => $this->options->getEncodedOption('window_title', ''), 'enableAttachmentsPanel' => $this->options->isOptionEnabled('enable_images_uploader') || $this->options->isOptionEnabled('enable_attachments_uploader'), 'enableImagesUploader' => $this->options->isOptionEnabled('enable_images_uploader'), 'enableAttachmentsUploader' => $this->options->isOptionEnabled('enable_attachments_uploader'), 'attachmentsExtensionsList' => $this->attachmentsService->getAllowedExtensionsList(), 'multilineSupport' => $this->options->isOptionEnabled('multiline_support'), 'hintMessage' => $this->options->getEncodedOption('hint_message'), 'messageMaxLength' => $this->options->getIntegerOption('message_max_length', 100), 'jsOptions' => json_encode($jsOptions), 'messagesOrder' => $this->options->getEncodedOption('messages_order', '') == 'descending' ? 'descending' : 'ascending', 'cssDefinitions' => $this->cssRenderer->getCssDefinition($chatId), 'customCssDefinitions' => $this->cssRenderer->getCustomCssDefinition()); $data = array_merge($data, $this->userSettingsDAO->getAll()); if ($this->authentication->isAuthenticated()) { $data = array_merge($data, $this->authentication->getUser()->getData()); } return $templater->render($data); }
/** * @throws WiseChatUnauthorizedAccessException */ private function checkUserAuthorization() { if ($this->options->getOption('access_mode') == 1 && !$this->usersDAO->isWpUserLogged()) { throw new WiseChatUnauthorizedAccessException('Access denied'); } }
/** * Publishes a message in the given channel of the chat and returns it. * * @param WiseChatUser $user Author of the message * @param WiseChatChannel $channel A channel to publish in * @param string $text Content of the message * @param boolean $isAdmin Indicates whether to mark the message as admin-owned * * @return WiseChatMessage|null * @throws Exception On validation error */ public function addMessage($user, $channel, $text, $isAdmin = false) { $text = trim($text); $filteredMessage = $text; // basic validation: if ($user === null) { throw new Exception('User cannot be null'); } if ($channel === null) { throw new Exception('Channel cannot be null'); } if ($this->bansService->isIpAddressBanned($user->getIp())) { throw new Exception($this->options->getOption('message_error_3', 'You were banned from posting messages')); } // use bad words filtering: if ($this->options->isOptionEnabled('filter_bad_words')) { WiseChatContainer::load('rendering/filters/pre/WiseChatFilter'); $badWordsFilterReplacement = $this->options->getOption('bad_words_replacement_text'); $filteredMessage = WiseChatFilter::filter($filteredMessage, strlen($badWordsFilterReplacement) > 0 ? $badWordsFilterReplacement : null); } // auto-ban feature: if ($this->options->isOptionEnabled('enable_autoban') && $filteredMessage != $text) { $counter = $this->abuses->incrementAndGetAbusesCounter(); $threshold = $this->options->getIntegerOption('autoban_threshold', 3); if ($counter >= $threshold && $threshold > 0) { $duration = $this->options->getIntegerOption('autoban_duration', 1440); $this->bansService->banIpAddress($user->getIp(), $this->bansService->getDurationFromString($duration . 'm')); $this->abuses->clearAbusesCounter(); } } // flood prevention feature: if ($this->options->isOptionEnabled('enable_flood_control')) { $floodControlThreshold = $this->options->getIntegerOption('flood_control_threshold', 200); $floodControlTimeFrame = $this->options->getIntegerOption('flood_control_time_frame', 1); if ($floodControlThreshold > 0 && $floodControlTimeFrame > 0) { $messagesAmount = $this->messagesDAO->getNumberByCriteria(WiseChatMessagesCriteria::build()->setIp($user->getIp())->setMinimumTime(time() - $floodControlTimeFrame * 60)); if ($messagesAmount > $floodControlThreshold) { $duration = $this->options->getIntegerOption('flood_control_ban_duration', 1440); $this->bansService->banIpAddress($user->getIp(), $this->bansService->getDurationFromString($duration . 'm')); } } } // go through the custom filters: $filterChain = WiseChatContainer::get('services/WiseChatFilterChain'); $filteredMessage = $filterChain->filter($filteredMessage); // cut the message: $messageMaxLength = $this->options->getIntegerOption('message_max_length', 100); if ($messageMaxLength > 0) { $filteredMessage = substr($filteredMessage, 0, $messageMaxLength); } // convert images and links into proper shortcodes and download images (if enabled): /** @var WiseChatLinksPreFilter $linksPreFilter */ $linksPreFilter = WiseChatContainer::get('rendering/filters/pre/WiseChatLinksPreFilter'); $filteredMessage = $linksPreFilter->filter($filteredMessage, $this->options->isOptionEnabled('allow_post_images'), $this->options->isOptionEnabled('enable_youtube')); $message = new WiseChatMessage(); $message->setTime(time()); $message->setAdmin($isAdmin); $message->setUserName($user->getName()); $message->setUserId($user->getId()); $message->setText($filteredMessage); $message->setChannelName($channel->getName()); $message->setIp($user->getIp()); if ($user->getWordPressId() !== null) { $message->setWordPressUserId($user->getWordPressId()); } $message = $this->messagesDAO->save($message); // mark attachments created by the links pre-filter: $createdAttachments = $linksPreFilter->getCreatedAttachments(); if (count($createdAttachments) > 0) { $this->attachmentsService->markAttachmentsWithDetails($createdAttachments, $channel->getName(), $message->getId()); } return $message; }