+2.84
Рейтинг
8.47
Сила

Олег

Добавлена поддержка РНР 7.4 для LiveStreet CMS

Обновил движки как первой так и второй версии для поддержки РНР 7.4. Плюс исправил некоторые ошибки. Можете написать, что ещё надо поправить.

LiveStreet 1.0.3
github.com/sersar/livestreet-1/tree/3fa6ae9d441092cd1b7b0e256e4ef7fc76431dbd

LiveStreet 2.1.0
github.com/livestreet/livestreet
github.com/sersar/livestreet-framework
(возможно позже внесут изменения в официальную ветку)

Просьба в комментариях ответить на вопросы:
  1. Будете ли обновлять движок до совместимости с РНР 7.4?
  2. Хотели бы внести какие-нибудь поправки в движок? Обновить библиотеки?
  3. Интересует адаптация/разработка плагинов в складчину?

P.S. Пишите по делу! Без больших постов и «умных» мыслей.

Желающим поддержать финансово можно здесь.

Чиним Пост-Опрос, Пост-Фотосет и Пост-Ссылка

Как вы уже заметили на 1.0.3 не работают «Пост-Опрос, Пост-Фотосет и Пост-Ссылка»

Чиним так. В файле: /classes/modules/topic/entity/Topic.entity.class.php

Заменить функции на вот эти:(Извеняйте, что не описал что именно менять, тут лимит стоит 15000. Но там всё идёт по порядку. Найдите начало и конец, и замените на этот код)
/**
     * Извлекает сериализованные данные топика
     */
    protected function extractExtra() {

        if (null === $this->aExtra) {
            $aData = @unserialize($this->getExtra());
            if (is_array($aData)) {
                $this->aExtra = $aData;
            }
        }
    }

    /**
     * Устанавливает значение нужного параметра
     *
     * @param string $sName    Название параметра/данных
     * @param mixed  $data     Данные
     */
    protected function setExtraValue($sName, $data) {

        $this->extractExtra();
        $this->aExtra[$sName] = $data;
        $this->setExtra($this->aExtra);
    }

    /**
     * Извлекает значение параметра
     *
     * @param string $sName    Название параметра
     *
     * @return null|mixed
     */
    protected function getExtraValue($sName) {

        $this->extractExtra();
        if (isset($this->aExtra[$sName])) {
            return $this->aExtra[$sName];
        }
        return null;
    }

    /* *** ******************** *** */
    /* *** SOURCE LINK OF TOPIC *** */

    /**
     * Returns URL of topic's source link
     *
     * @param bool $bShort    Shorten URL
     *
     * @return null|string
     */
    public function getSourceLink($bShort = false) {

        if ($sUrl = $this->getExtraValue('url')) {
            if ($bShort) {
                $sUrl = htmlspecialchars($sUrl);
                if (preg_match('/^https?:\/\/(.*)$/i', $sUrl, $aMatch)) {
                    $sUrl = $aMatch[1];
                }
                $sUrlShort = substr($sUrl, 0, 30);
                if (strlen($sUrlShort) != strlen($sUrl)) {
                    return $sUrlShort . '...';
                }
                return $sUrl;
            } else {
                if (!preg_match('/^https?:\/\/(.*)$/i', $sUrl, $aMatch)) {
                    $sUrl = 'http://' . $sUrl;
                }
            }
            return $sUrl;
        }
        return null;
    }

    /**
     * Set URL of topic's source link
     *
     * @param string $data
     */
    public function setSourceLink($data) {

        $this->setExtraValue('url', strip_tags($data));
    }

    /**
     * Возвращает количество переходов по ссылке в топике-ссылке
     *
     * @return int
     */
    public function getSourceLinkCountJump() {

        return (int)$this->getExtraValue('count_jump');
    }

    /**
     * Устанавливает количество переходов по ссылке в топике-ссылке
     *
     * @param string $data
     */
    public function setSourceLinkCountJump($data) {

        $this->setExtraValue('count_jump', $data);
    }

    /* *** ********************** *** */
    /* *** QUESTIONNAIRE OF TOPIC *** */

    /**
     * Устанавливает вопрос
     *
     * @param string $data
     */
    public function setQuestionTitle($data) {

        $this->setExtraValue('question_title', $data);
    }

    /**
     * Возвращает вопрос, если вопрос не указан - заголовок топика
     *
     * @return int|null
     */
    public function getQuestionTitle() {

        if ($this->getExtraValue('question_title')) {
            return $this->getExtraValue('question_title');
        }
        return $this->getTitle();
    }

    /**
     * Добавляет вариант ответа в опросе топика
     *
     * @param string $data
     */
    public function addQuestionAnswer($data) {

        $this->extractExtra();
        $this->aExtra['answers'][] = array('text' => $data, 'count' => 0);
        $this->setExtra($this->aExtra);
    }

    /**
     * Очищает варианты ответа в опросе топика
     */
    public function clearQuestionAnswer() {

        $this->setExtraValue('answers', array());
    }

    /**
     * Возвращает варианты ответа в опросе топика
     *
     * @param bool $bSortVote
     *
     * @return array|null
     */
    public function getQuestionAnswers($bSortVote = false) {

        $aAnswers = $this->getExtraValue('answers');
        if ($aAnswers && $bSortVote) {
            uasort(
                $aAnswers, create_function(
                    '$a,$b',
                    "if (\$a['count'] == \$b['count']) { return 0; } return (\$a['count'] < \$b['count']) ? 1 : -1;"
                )
            );
        }
        return $aAnswers ? $aAnswers : array();
    }

    /**
     * Увеличивает количество ответов на данный вариант в опросе топика
     *
     * @param int $sIdAnswer  ID варианта ответа
     */
    public function increaseQuestionAnswerVote($sIdAnswer) {

        if ($aAnswers = $this->getQuestionAnswers()) {
            if (isset($aAnswers[$sIdAnswer])) {
                $aAnswers[$sIdAnswer]['count']++;
                $this->aExtra['answers'] = $aAnswers;
                $this->setExtra($this->aExtra);
            }
        }
    }

    /**
     * Возвращает максимально количество ответов на вариант в опросе топика
     *
     * @return int
     */
    public function getQuestionAnswerMax() {

        $aAnswers = $this->getQuestionAnswers();
        $iMax = 0;
        foreach ($aAnswers as $aAns) {
            if ($aAns['count'] > $iMax) {
                $iMax = $aAns['count'];
            }
        }
        return $iMax;
    }

    /**
     * Возвращает в процентах количество проголосовавших за конкретный вариант
     *
     * @param int $sIdAnswer ID варианта
     *
     * @return int|string
     */
    public function getQuestionAnswerPercent($sIdAnswer) {

        if ($aAnswers = $this->getQuestionAnswers()) {
            if (isset($aAnswers[$sIdAnswer])) {
                $iCountAll = $this->getQuestionCountVote() - $this->getQuestionCountVoteAbstain();
                if (!$iCountAll == 0) {
                    return number_format(round($aAnswers[$sIdAnswer]['count'] * 100 / $iCountAll, 1), 1, '.', '');
                }
            }
        }
        return 0;
    }

    /**
     * Возвращает общее число принявших участие в опросе в опросе топика
     *
     * @return int
     */
    public function getQuestionCountVote() {

        return (int)$this->getExtraValue('count_vote');
    }

    /**
     * Устанавливает общее число принявших участие в опросе в опросе топика
     *
     * @param int $data
     */
    public function setQuestionCountVote($data) {

        $this->setExtraValue('count_vote', $data);
    }

    /**
     * Возвращает число воздержавшихся от участия в опросе
     *
     * @return int
     */
    public function getQuestionCountVoteAbstain() {

        return (int)$this->getExtraValue('count_vote_abstain');
    }

    /**
     * Устанавливает число воздержавшихся от участия в опросе
     *
     * @param int $data
     *
     * @return mixed
     */
    public function setQuestionCountVoteAbstain($data) {

        $this->setExtraValue('count_vote_abstain', $data);
    }
/**
	 * Возвращает фотографии из топика-фотосета
	 *
	 * @param int|null $iFromId	ID с которого начинать  выборку
	 * @param int|null $iCount	Количество
	 * @return array
	 */
	public function getPhotosetPhotos($iFromId = null, $iCount = null) {
		return $this->Topic_getPhotosByTopicId($this->getId(), $iFromId, $iCount);
	}
	/**
	 * Возвращает количество фотографий в топике-фотосете
	 *
	 * @return int|null
	 */
	public function getPhotosetCount() {
		return $this->getExtraValue('count_photo');
	}
	/**
	 * Возвращает ID главной фото в топике-фотосете
	 *
	 * @return int|null
	 */
	public function getPhotosetMainPhotoId() {

        $oImage = $this->getPhotosetMainPhoto();
        if ($oImage) {
            return $oImage->getMresourceId();
        }

        return $this->getExtraValue('main_photo_id');
    }
	/**
	 * Устанавливает ID главной фото в топике-фотосете
	 *
	 * @param int $data
	 */
	public function setPhotosetMainPhotoId($iPhotoId) {

        $this->setExtraValue('main_photo_id', $iPhotoId);
        $this->setProp('_photoset_photos', null);
    }
	/**
	 * Устанавливает количество фотографий в топике-фотосете
	 *
	 * @param int $data
	 */
	public function setPhotosetCount($iCount) {

        $this->setExtraValue('count_photo', $iCount);
        $this->setProp('_photoset_photos', null);
    }

Не дадим 1.0.3 умереть!

Вставка видео через ссылку Youtube, mp4, avi, webm, flv и т.д.(Готовое решение)

Поддержка видео для таких сайтов как:
  • youtube.com
  • vimeo.com
  • rutube.ru
  • coub.com
  • ok.ru
  • vk.com
  • dailymotion.com

Для: LS 1.0.3

В /engine/modules/text/Text.class.php

Меняем функцию public function VideoParser($sText)

На это:
public function VideoParser($sText) {
		
		// Размеры и атрибуты окна вставленного видео.
        $iWidth = 620;
        $iHeight = 360;
        $iAlign = "center";
        $sIframeAttr = 'frameborder="0" webkitAllowFullScreen mozallowfullscreen allowfullscreen="allowfullscreen"';
		/**
         * youtube.com fixed
         */
        $sText = preg_replace(
        '/<video>(?:http(?:s|):|)(?:\/\/|)(?:www\.|m.|)youtu(?:\.|)be(?:-nocookie|)(?:\.com|)\/(?:e(?:mbed|)\/|v\/|watch\?(?:.+&|)v=|)([a-zA-Z0-9_\-]+?)(&.+)?<\/video>/Ui',
        '<div align="'.$iAlign.'"><iframe width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.' src="//www.youtube.com/embed/$1?modestbranding=1&" frameborder="0" allowfullscreen ></iframe></div>',
        $sText
        );
		/**
         * vimeo.com fixed
         */
        $sText = preg_replace(
		    '/<video>http(?:s|):\/\/(?:www\.|)vimeo\.com\/(\d+).*<\/video>/i',
            '<div align="'.$iAlign.'"><iframe src="//player.vimeo.com/video/$1" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>',
            $sText
        );
		/**
         * rutube.ru fixed
         */
        $sText = preg_replace(
            '/<video>http(?:s|):\/\/(?:www\.|)rutube\.ru\/tracks\/(\d+)\.html.*<\/video>/Ui',
            '<div align="'.$iAlign.'"><iframe src="//rutube.ru/play/embed/$1" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>',
            $sText
        );
        $sText = preg_replace(
            '/<video>http(?:s|):\/\/(?:www\.|)rutube\.ru\/video\/(\w+)\/?<\/video>/Ui',
            '<div align="'.$iAlign.'"><iframe src="//rutube.ru/play/embed/$1" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>',
            $sText
        );
		/**
	    * coub.com fixed
	    */
	    $sText = preg_replace(
		    '/<video>http(?:s|):\/\/(?:www\.|)coub\.com\/view\/(\w+).*<\/video>/i', 
		    '<div align="'.$iAlign.'"><iframe src="//coub.com/embed/$1?muted=false&autostart=false&originalSize=false&hideTopBar=false&noSiteButtons=false&startWithHD=false" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>', 
		$sText
		);
		/**
	    * ok.ru fixed
	    */
	    $sText = preg_replace(
		    '/<video>http(?:s|):\/\/(?:www\.|)ok\.ru\/video\/(\w+).*<\/video>/i', 
		    '<div align="'.$iAlign.'"><iframe src="//ok.ru/videoembed/$1" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>', 
		$sText
		);
		/**
	    * vk.com HASH not working, embeded link only
	    */
		$sText = preg_replace(
		    '/<video>(https:\/\/(?:www\.|)vk\.com\/video_ext\.php.*)<\/video>/i', 
			'<div align="'.$iAlign.'"><iframe src="$1" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>', 
		$sText
		);
            /**
	    * dailymotion.com fixed
	    */
	    $sText = preg_replace(
		    '/<video>http(?:s|):\/\/(?:www\.|)dai\.ly\/(\w+).*<\/video>/i', 
		    '
<div align="'.$iAlign.'"><iframe src="//dailymotion.com/embed/video/$1" width="'.$iWidth.'" height="'.$iHeight.'" '.$sIframeAttr.'></iframe></div>', 
		$sText
		);
		return $sText;
	}

Конечно же в /config/jevix.php добавляем нехватающие сайты.

Свои параметры сюда:
// Размеры и атрибуты окна вставленного видео.
        $iWidth = 620;
        $iHeight = 360;
        $iAlign = "center";
        $sIframeAttr = 'frameborder="0" webkitAllowFullScreen mozallowfullscreen allowfullscreen="allowfullscreen"';


Готово!

Метод GetCountCommentsByUserId не кеширует данные (LiveStreet 1.0.3)

Привет!
В поисках причины генерации страницы профиля более одной секунды в методе GetCountCommentsByUserId была найдена проблема. При большом количестве топиков скорость генерации страниц падает. Запрос проходил по 0.7 секунд.
Вместо:
public function GetCountCommentsByUserId($sId,$sTargetType) {
		/**
		 * Исключаем из выборки идентификаторы закрытых блогов
		 */
		$aCloseBlogs = ($this->oUserCurrent && $sId==$this->oUserCurrent->getId())
			? array()
			: $this->Blog_GetInaccessibleBlogsByUser();
		$s=serialize($aCloseBlogs);

		if (false === ($data = $this->Cache_Get("comment_count_user_{$sId}_{$sTargetType}_{$s}"))) {
			$data = $this->oMapper->GetCountCommentsByUserId($sId,$sTargetType,array(),$aCloseBlogs);
			$this->Cache_Set($data, "comment_count_user_{$sId}_{$sTargetType}", array("comment_new_user_{$sId}_{$sTargetType}","comment_update_status_{$sTargetType}"), 60*60*24*2);
		}
		return $data;
	}
Заменить на:
public function GetCountCommentsByUserId($sId,$sTargetType) {
		/**
		 * Исключаем из выборки идентификаторы закрытых блогов
		 */
		$aCloseBlogs = ($this->oUserCurrent && $sId==$this->oUserCurrent->getId())
			? array()
			: $this->Blog_GetInaccessibleBlogsByUser();
		$s=serialize($aCloseBlogs);

		if (false === ($data = $this->Cache_Get("comment_count_user_{$sId}_{$sTargetType}_{$s}"))) {
			$data = $this->oMapper->GetCountCommentsByUserId($sId,$sTargetType,array(),$aCloseBlogs);
			$this->Cache_Set($data, "comment_count_user_{$sId}_{$sTargetType}_{$s}", array("comment_new_user_{$sId}_{$sTargetType}","comment_update_status_{$sTargetType}"), 60*60*24*2);
		}
		return $data;
	}

В версии LiveStreet 2.* это исправлено.

Создание простого плагина. Пошаговая инструкция для новичков. Часть 1

Данный материал предназначен для новичков в мире Livestreet, желающих разобраться с базовыми особенностями работы с системой плагинов.

Создадим простой плагин, который будет создавать объект «Book» из введенных пользователем данных и сохранять в базу данных. А на отдельной страничке — выводить все созданные объекты Book списком.

Читать дальше →

Плагин для блокировки и автоматического удаления спамеров/ботов "Total Антиспам"

4 фото
image
Представляю вашему вниманию плагин «Total Антиспам», который призван защитить ваш сайт от ботов и ручного спама, а также удалить с сайта уже действующих и неактивных ботов в автоматическом режиме.


Из возможностей плагина:
— JS защита форм регистрации, написания топика, комментария, личного сообщения.
— Установка и проверка капчи при написании топиков, комментариев, личных сообщений
— Возможность блокировки топиков/комментариев/личных сообщений/записей на стене, содержащих ссылки.
— Возможность установки вышеперечисленных ограничений по уровню рейтинга пользователя.
— Возможность проверки публикуемых комментариев и записей на стене по базе Akismet.
— Возможность запрещать размещение ссылок в профиле
— Проверка почты и IP по базе stopforumsapm.com при регистрации.
— Проверка почты и IP по базе stopforumsapm.com при написании топика/комментария/личного сообщения/записи на стене.
— Возможность автоматической отправки новых спамеров в базу stopforumsapm.com
— Периодическая проверка по расписанию всех пользователей по базе stopforumsapm.com
— Возможность автоматического удаления найденных спамеров по расписанию или в ручном режиме
— Удобная панель настройки без необходимости правки конфигов

Получить скидку
Сообщить о проблеме или ошибке

TinyMCE 4 для LiveStreet 1.0

Здравствуйте.
Недавно у меня возникла острая необходимость в замене стандартного редактора TinyMCE (LiveStreet 1.0.3) на более новую версию. И так как стандартного решения на сайте не нашел (согласен, возможно плохо искал), то представляю Вашему вниманию небольшой плагин которым я постарался решить эту задачу. Возможно он и поможет кому-то из пользователей.

Читать дальше →

Как вынести количество публикаций каждого пользователя на страницу пользователей

Данный топик — расширенный ответ на вопрос, заданный в этом топике т.к. мне уже не первый раз задают этот вопрос.

Нужно в файле сущности пользователя \classes\modules\user\entity\User.entity.class.php (например, после 453 строки) дописать метод:
/**
 * Возвращает количество созданных пользователем топиков и комментариев
 *
 * @return int
 */
public function getPublicationsCount() {
  $iCountTopicUser = $this->Topic_GetCountTopicsPersonalByUser($this->getId(), 1);
  $iCountCommentUser = $this->Comment_GetCountCommentsByUserId($this->getId(), 'topic');
  return $iCountTopicUser + $iCountCommentUser;
}


Читать дальше →