<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
			<channel>
			<title>Alto CMS/Блог им. 135</title>
			<link>http://79.174.14.219/profile/135/created/topics/</link>
			<description><![CDATA[Это ваш персональный блог.]]></description>
			<language>ru</language>
			<managingEditor>anp135@gmail.com</managingEditor>
			<webMaster>noreply@altocms.ru</webMaster>
			<generator>Alto CMS v.1.5.0b1</generator>
							<item>
					<title>Кросс-доменная авторизация AltoCMS + PhpBB</title>
					<guid isPermaLink="true">http://79.174.14.219/t/937/</guid>
					<link>http://79.174.14.219/937.html</link>
					<author>anp135@gmail.com</author>
					<description><![CDATA[Когда систем становится больше чем одна но меньше чем множество, приходит пора задуматься о том, как же жить дальше. Правильное и красивое решение — перейти на следующий уровень и запилить авторизацию всех систем через единый паспорт-хост. Но что делать, когда такие крупномасштабные изменения не целесообразны, но в тоже время как-то надо увязать CMS и, к примеру, форум? Если:<br>
— системы расположены в одном домене второго уровня;<br>
— БД в идеале находятся в на одном сервере (как минимум в скриптовой доступности);<br>
— FE в идеале на одном сервере.<br>
<br>
В таком случае можно сходить по пути минимализма и реализовать кросс-доменную авторизацию в рамках СУБД. Как правило небольшие подобные системы для хранения данных используют MySQL, а обрабатывают эти данные <s>исключительно</s> в основном в PHP. В тоже время MySQL уже вырос из простого хранилища в более-менее СУБД.<br>
<br>
Чтобы реализовать сабж, нам надо результат авторизации (а это, обычно, данные в БД + cookies + php session данные) сделать доступными для <s>обоих</s> всех систем.<br>
<br>
С данными БД проще всего — при помощи триггеров и (в особо сложных случаях) хранимых процедур организовываем двухстороннюю репликацию данных. Чтобы не пришлось переписывать одну или несколько систем, а пользователи не потеряли свои пароли и данные, необходимо:<br>
— во всех системах реализовать единый механизм хеширования паролей;<br>
— реализовать плавную репликацию юзерских данных (как минимум таблица пользователей) из исходной в остальные системы;<br>
— реализовать репликацию сессионных данных, хранящихся в БД между всеми системами.<br>
<br>
С cookies чуть сложнее. Древние системы, бывает, работают не в стандартной PHP сессии, а хранят всё подряд в куках. Здесь надо выбирать, или в код каждой системы вносить генерацию кукисов для всех остальных, или запилить авторизацию таким образом, чтобы каждая система восстанавливала свои куки сама из БД по ключу из PHP сессии. Я пошел по второму варианту. <br>
Формироваться cookies должны для корневого домена второго уровня дабы быть доступными для всех систем (как минимум идентификатор PHP сессии).<br>
<br>
PHP сессии. В наиболее удобной системе добавляем в процесс авторизации извлечение из БД в PHP сессию первичных ключей для всех систем (как правило это user_id&#39;ы). Затем останется только минимально вмешаться в код и научить каждую систему брать из PHP сессии необходимые первичные ключи и восстанавливать все остальные данные (куки).<br>
<br>
Репликацию каждый с каждым можно настроить как через сводную таблицу, так и напрямую. Во втором случае (по которому пошёл я) надо для передачи репликационных ключей либо добавлять поле, либо аккуратно использовать имеющиеся не используемые :). Идея проста — если данные пришли из другой системы, то триггер завершается, если же данные пришли из веба — триггер реплицирует данные по остальным системам.<br>
<br>
В более сложных случаях географическую удалённость FE и BE можно преодолеть через фичу выполнения скрипта из СУБД.<br>
<br>
В итоге получаем кросс-доменную авторизацию через любую из систем. Максимальное быстродействие при минимальном вмешательстве в код.]]></description>
					<pubDate>Mon, 12 Jan 2015 13:13:52 +0300</pubDate>
									</item>
							<item>
					<title>AltoCMS + phpBB: интеграция auth</title>
					<guid isPermaLink="true">http://79.174.14.219/t/903/</guid>
					<link>http://79.174.14.219/903.html</link>
					<author>anp135@gmail.com</author>
					<description><![CDATA[Чтобы начать интеграцию или переезд с любой другой системой (в данном случае phpBB), необходимо в первую очередь научить <a href="https://altocms.ru/871.html" title="<strong>Alto&nbsp;</strong><br>Если вы собираетесь создавать сайт и выбираете для этой цели CMS (или «движок», как еще говорят), то наверняка у вас возникает вопрос: «А чем же Alto лучше других CMS? И годится ли для моих задач?»&lt;br/&gt;
&lt;br/&gt;
Выбирая Alto CMS, вы получаете «из коробки» функционал, который в других движках достигается установкой множества плагинов:" class="term">Alto</a> сверять пароли с уже имеющимися хешами источника.<br>
<s><strong>common/classes/modules/user/<a href="https://altocms.ru/1585.html" title="<strong>Entity&nbsp;</strong><br>Сущность – это некий набор данных, которые называют «свойствами» (property). Например, сущность «Пользователь» (User) имеет такие свойства, как идентификатор, логин, адрес электронной почты, и т.д." class="term">entity</a>/User.<a href="https://altocms.ru/1585.html" title="<strong>Entity&nbsp;</strong><br>Сущность – это некий набор данных, которые называют «свойствами» (property). Например, сущность «Пользователь» (User) имеет такие свойства, как идентификатор, логин, адрес электронной почты, и т.д." class="term">entity</a>.class.php</strong><br>
Сюда из auth библиотеки phpBB необходимо добавить функции формирования и проверки хеша:<br>
<pre class="prettyprint"><code>
phpbb_hash()
phpbb_check_hash()
_hash_gensalt_private()
_hash_encode64()
_hash_crypt_private()
unique_id()
</code></pre><br>
<br>
и немного подкрутить setPassword():<br>
<pre class="prettyprint"><code>
   public function setPassword($sPassword, $bEncrypt = false) {

        if ($bEncrypt) {
            //$this-&#62;_aData[&#39;user_password&#39;] = $this-&#62;Security_Salted($sPassword, &#39;pass&#39;);
            $this-&#62;_aData[&#39;user_password&#39;] = $this-&#62;phpbb_hash($sPassword);
        } else {
            $this-&#62;setProp(&#39;user_password&#39;, $sPassword);
        }
    }
</code></pre><br>
<br>
И в экшене логина <strong>common/classes/actions/ActionLogin.class.php</strong><br>
меняем механизм проверки хеша:<br>
<pre class="prettyprint"><code>            // * Сверяем хеши паролей и проверяем активен ли юзер
            //if ($this-&#62;Security_CheckSalted($oUser-&#62;getPassword(), $sUserPassword, &#39;pass&#39;) || $this-&#62;Security_CheckSalted($oUser-&#62;getPassword(), trim($sUserPassword), &#39;pass&#39;)) {
            if ($oUser-&#62;phpbb_check_hash(trim($sUserPassword), $oUser-&#62;getPassword())) {
</code></pre></s><br>
<br>
Ставим <a href="https://altocms.ru/addons/item/111/">плагин</a> и связки юзер+пароль из БД phpBB будут работать.<br>
<br>
По аналогии можно запилить поддержку auth механизмов и соответственно уже имеющихся пользователей любых других CMS / форумов / чего угодно. В <a href="https://altocms.ru/1585.html" title="<strong>Entity&nbsp;</strong><br>Сущность – это некий набор данных, которые называют «свойствами» (property). Например, сущность «Пользователь» (User) имеет такие свойства, как идентификатор, логин, адрес электронной почты, и т.д." class="term">entity</a> добавляем механизм формирования хеша, в actionLogin — проверку.<br>
<br>
Важно понимать, что это только всего лишь адаптация проверки пароля захешированного в phpbb(ex), если вам нужна реальная интеграция двух систем, это всего лишь перввый шажочек по данному направлению.]]></description>
					<pubDate>Sat, 20 Dec 2014 20:08:38 +0300</pubDate>
									</item>
							<item>
					<title>Локальные URL - грабли №2</title>
					<guid isPermaLink="true">http://79.174.14.219/t/680/</guid>
					<link>http://79.174.14.219/680.html</link>
					<author>anp135@gmail.com</author>
					<description><![CDATA[Вступив не неблагодарный путь работы с локальными URL (URL в рамках данного хоста без <a href="http://hostname/)" rel="nofollow">http://hostname/)</a> я ошибочно полагал что все проблемы закончатся на <a href="https://altocms.ru/644.html">исправлении данных в БД</a> (здесь я типа обратился к сайдбару, в котором по ajax нашел ссылку на статью или какой другой объект и вставил в текст). Но не тут то было... Следующая грабля поджидает нас при попытке генерить изображения различных размеров. В частности <strong>common/plugins/topicintro/classes/modules/topic/<a href="https://altocms.ru/1585.html" title="<strong>Entity&nbsp;</strong><br>Сущность – это некий набор данных, которые называют «свойствами» (property). Например, сущность «Пользователь» (User) имеет такие свойства, как идентификатор, логин, адрес электронной почты, и т.д." class="term">entity</a>/Topic.<a href="https://altocms.ru/1585.html" title="<strong>Entity&nbsp;</strong><br>Сущность – это некий набор данных, которые называют «свойствами» (property). Например, сущность «Пользователь» (User) имеет такие свойства, как идентификатор, логин, адрес электронной почты, и т.д." class="term">entity</a>.class.php</strong>—&#62;getPreviewImageUrl() спотыкается на проверке <strong><em>if (F::File_IsLocalUrl($sUrl))</em></strong> и далее соответственно возвращает просто URL на исходник и тяни его CSS как хочешь.<br>
<br>
Такое поведение происходит по целому ряду причин. В первую очередь это false в <strong>engine/include/functions/File.php</strong>—&#62;LocalPath()<br>
не нашел ничего лучше чем закостылить:<br>
<pre class="prettyprint"><code>
    static public function LocalPath($sPath, $xRoot) {

        $xResult = false;
        if (is_array($xRoot)) {
            foreach ($xRoot as $sRoot) {
                $xResult = static::LocalPath($sPath, $sRoot);
                if ($xResult) {
                    return $xResult;
                }
            }
            return $xResult;
        } else {
            $sRoot = (string)$xRoot;
        }
        if ($sPath &#38;&#38; $sRoot) {
            $sPath = static::NormPath($sPath);
            $sRoot = static::NormPath($sRoot . &#39;/&#39;);
            //135
            // костылим local URL
            if (substr($sPath, 0, 1) === &#39;/&#39;)
                return substr($sPath, strlen($sRoot));
            elseif (strpos($sPath, $sRoot) === 0 || strpos($sPath . &#39;/&#39;, $sRoot) === 0) {
                return substr($sPath, strlen($sRoot));
            }
        }
        return $xResult;
    }
</code></pre><br>
<br>
Следующая грабля поджидает в <strong>engine/include/functions/File.php</strong>:ImgModSuffix(). Тут уже интереснее. Здесь потерпят фиаско уже не только попытки работы с local URL, но и все, кто попробует задать высоту вместе с шириной [и с crop/fit/pad]. Вносим минимальные правки — добавляем второй делитель и исправляем экстракцию высоты:<br>
<pre class="prettyprint"><code>
    static public function ImgModSuffix($xSize = null, $sExtension = null) {

        $sResult = &#39;&#39;;
        $nPos = strpos($xSize, &#39;x&#39;);
        $mPos = strpos($xSize, &#39;-&#39;);
        if ($nPos === false) {
            $nHeight = $nWidth = intval($xSize);
        } elseif ($nPos === 0) {
            $nWidth = 0;
            $nHeight = intval(substr($xSize, 1));
        } else {
            $nWidth = intval(substr($xSize, 0, $nPos));
            $mPos ? $nHeight = intval(substr($xSize, $nPos + 1, $mPos)) : $nHeight = intval(substr($xSize, $nPos + 1));
        }
        if ($nWidth || $nHeight) {
            $sResult .= &#39;-&#39; . ($nWidth ? $nWidth : &#39;&#39;) . &#39;x&#39; . $nHeight;
            if (strpos($xSize, &#39;fit&#39;)) {
                $sResult .= &#39;-fit&#39;;
            } else if (strpos($xSize, &#39;crop&#39;)) {
                $sResult .= &#39;-crop&#39;;
            } else if (strpos($xSize, &#39;pad&#39;)) {
                $sResult .= &#39;-pad&#39;;
            }
            if ($sExtension) {
                $sResult .= &#39;.&#39; . strtolower($sExtension);
            }
        }
        return $sResult;
    }
</code></pre><br>
<br>
Теперь получаем правильное имя файла, но если у нас его пока ещё нет, то чтобы он генерился в случае local URL нам надо в <strong>engine/include/functions/File.php</strong>—&#62;Url2Dir() этот local URL закостылить, иначе проверка исходника на существование не пройдёт и <strong>$this-&#62;Img_Duplicate($sFile)</strong> в <strong>getPreviewImageUrl()</strong> не случится.]]></description>
					<pubDate>Sat, 26 Jul 2014 14:36:41 +0400</pubDate>
									</item>
							<item>
					<title>Замена подстроки в сериализованных данных БД</title>
					<guid isPermaLink="true">http://79.174.14.219/t/644/</guid>
					<link>http://79.174.14.219/644.html</link>
					<author>anp135@gmail.com</author>
					<description><![CDATA[Наступив на заботливо подложенные авторами грабли в виде хранения путей к изображениям в абсолютном виде (<a href="http://..." rel="nofollow">http://...</a>) — исправляем данные в БД. Просто замена подстроки в поле таблицы не вызывает трудностей, а вот внести исправления в сериализованные данные при помощи одного только phpmyadmin не получится. Функция на примере таблицы <strong>prefix_topic_content</strong> и поля <strong>topic_extra</strong>.<br>
<pre class="prettyprint"><code>    public function RecalculateTopicExtra($search, $replace) {
        $upcount = 0;
        $sql = &#34;SELECT topic_id, topic_extra FROM prefix_topic_content&#34;;
        $aRows = $this-&#62;oDb-&#62;select($sql);
        if($aRows = $this-&#62;oDb-&#62;select($sql))
        {
            foreach($aRows as $aRow)
            {
                $topic_id = $aRow[&#39;topic_id&#39;];
                $topic_extra = str_replace($search, $replace, unserialize($aRow[&#39;topic_extra&#39;]), $rcount);
                if ($rcount &#62; 0)
                {
                    $sql = &#34;UPDATE prefix_topic_content SET topic_extra = &#39;&#34; . serialize($topic_extra) . &#34;&#39; WHERE topic_id = &#34; . $topic_id;
                    $this-&#62;oDb-&#62;query($sql);
                    $upcount++;
                }
            }
        }
        return $upcount;
    }</code></pre>]]></description>
					<pubDate>Wed, 23 Jul 2014 01:54:43 +0400</pubDate>
									</item>
							<item>
					<title>Плагин Alian2 - запуск под Alto 1.0</title>
					<guid isPermaLink="true">http://79.174.14.219/t/636/</guid>
					<link>http://79.174.14.219/636.html</link>
					<author>anp135@gmail.com</author>
					<description><![CDATA[Чтобы заработал этот <s>говнокод</s> плагин необходимо следующее: 1. Вставить в форму шаблона редактирования/создания топика набор полей для загрузки изображений.<br>
<br>
Ошибочно полагать виджет alian формой для загрузки картинок, на самом деле виджет используется только для отображения уже загруженных картинок и вставки их в текст топика (заметки).<br>
<br>
Находим в <strong>common/plugins/alian/templates/skin/default/actions/ActionContent/add.tpl</strong> <pre class="prettyprint"><code>&#60;fieldset class=&#34;topic-fieldset alian&#34;&#62;
-----
&#60;/fieldset&#62;</code></pre><br>
<br>
и вырезаем в <strong>common/templates/skin/start-kit/tpls/fields/field.alian.tpl</strong>, добавляем в <br>
<strong>common/templates/skin/start-kit/tpls/topics/topic.type_default-edit.tpl</strong> по вкусу (я вставил под загрузкой картинок в фотосет).<br>
<br>
2. Фиксим JS<br>
<br>
В первой строке <strong>common/plugins/alian/templates/skin/default/js/aln_uploader.js</strong> автор плагина честно врёт за копирайт, на самом деле пошукав в сети можно убедиться что код этот он не сочинил а честно <s>спиздил</s> переиспользовал.<br>
<br>
Всю конструкцию от <pre class="prettyprint"><code>self.xhr.open(&#34;POST&#34;, params.url);</code></pre> и ниже следует заменить на<br>
<pre class="prettyprint"><code>        var boundary = SESSION_ID;
        var topic_id = $(&#34;#topic_id&#34;).val();
        if (self.xhr.sendAsBinary)
        {
            //Firefox
            self.xhr.setRequestHeader(&#34;Content-Type&#34;, &#34;multipart/form-data, boundary=&#34;+boundary);
            self.xhr.setRequestHeader(&#34;Cache-Control&#34;, &#34;no-cache&#34;);
            self.xhr.setRequestHeader(&#34;X-Requested-With&#34;, &#34;XMLHttpRequest&#34;);
            self.xhr.setRequestHeader(&#34;topic_id&#34;, topic_id);

            var body = &#34;--&#34; + boundary + &#34;\r\n&#34;;
            body += &#34;Content-Disposition: form-data; name=&#39;security_key&#39;\r\n\r\n&#34;;
            body += ALTO_SECURITY_KEY + &#34;\r\n&#34;;
            body += &#34;--&#34; + boundary + &#34;\r\n&#34;;

            body += &#34;Content-Disposition: form-data; name=&#39;&#34;+(params.fieldName || &#39;file&#39;)+&#34;&#39;; filename=&#39;&#34; + params.file.name + &#34;&#39;\r\n&#34;;
            body += &#34;Content-Type: application/octet-stream\r\n\r\n&#34;;
            body += self.reader.result + &#34;\r\n&#34;;
            body += &#34;--&#34; + boundary + &#34;--&#34;;
            self.xhr.sendAsBinary(body);
        } else {
            // chrome (W3C spec.)
            var formData = new FormData();
            self.xhr.setRequestHeader(&#34;Cache-Control&#34;, &#34;no-cache&#34;);
            self.xhr.setRequestHeader(&#34;X-Requested-With&#34;, &#34;XMLHttpRequest&#34;);
            formData.append((params.fieldName || &#39;files&#39;), params.file);
            formData.append(&#39;security_key&#39;, ALTO_SECURITY_KEY);
            formData.append(&#39;topic_id&#39;, topic_id);
            self.xhr.send(formData);
        }</code></pre><br>
<br>
Для FF ввиду того, что он в головоной Content-Type вместо multipart-data/form пишет text/plain — приходится собирать запрос руками. Для Chrome и Opera достаточно сделать append security ключа.<br>
—<br>
<br>
Не забыть скопировать jevix.local.php согласно «инструкции» автора, конфиг в apps/ и правильно настроить параметры виджета.<br>
<br>
<strong>P.S.</strong> Это только первичный запуск плагина. На самом деле ещё куча работы по верификации кода, исправлению отображения кнопки delete в виджете, правильной генерации версий с различными размерами (щас тупо генерит все размеры не глядя на исходник), более корректной вставки в код статьи (не тупой <strong>a href+img src</strong>, а превью с/без полной версией под JS), возможно доработке кода групповой загрузки изображений (форма мультипарт, а файлы грузятся строго по одному) и вынос в конфиг параметра «пачка/по одному» для быстрых каналов, и т.д. и т.п.<br>
<br>
Вот что 300 рублей животворящие делают —), так бы выкинул это говно и забыл бы...]]></description>
					<pubDate>Sat, 19 Jul 2014 02:43:54 +0400</pubDate>
									</item>
							<item>
					<title>Встраивание карт в заметки (топики).</title>
					<guid isPermaLink="true">http://79.174.14.219/t/582/</guid>
					<link>http://79.174.14.219/582.html</link>
					<author>anp135@gmail.com</author>
					<description><![CDATA[<h6>Введение.</h6>
Кратко, без лишних слов, чтобы не забыть в будущем.<br>
<br>
Сервис карт можно использовать в принципе любой, но мне больше по душе основанный на Leaflet <a href="http://mapbbcode.org" rel="nofollow">MapBBCode</a>. По умолчанию в Альто (как и в Livestreet) в MarkItUp используется Html разметка. Не буду ломать лишнего и добавлю свой тег который в будущем буду расширять списком поддерживаемых типов встраивания.<br>
<h6>Порядок действий.</h6>
1. Либо пользуемся <a href="http://share.mapbbcode.org" rel="nofollow">http://share.mapbbcode.org</a>, либо устанавливаем свою копию. <br>
<br>
2. Добавляем кнопку в MarkItUp.<br>
<strong>templates/framework/js/settings.js</strong><br>
<pre class="prettyprint"><code>
        this.getMarkitup = function() {
                return {
                        onShiftEnter:   {keepDefault:false, replaceWith:&#39;&#60;br /&#62;\n&#39;},
                        onCtrlEnter:    {keepDefault:false, openWith:&#39;\n&#60;p&#62;&#39;, closeWith:&#39;&#60;/p&#62;&#39;},
                        onTab:                  {keepDefault:false, replaceWith:&#39;    &#39;},
                        markupSet:  [
------------
                                {name: ls.lang.get(&#39;panel_media&#39;), className:&#39;editor-media&#39;, replaceWith:&#39;&#60;media&#62;[![&#39;+ls.lang.get(&#39;panel_media_promt&#39;)+&#39;:!:http://]!]&#60;/media&#62;&#39; }
                        ]
                }
        };
</code></pre><br>
<strong>engine/lib/external/jquery/markitup/sets/default/style.css</strong><br>
Добавляем класс для кнопки<br>
<br>
<strong>engine/lib/external/jquery/markitup/sets/default/images</strong><br>
Размещаем иконку кнопки<br>
<br>
<strong>engine/modules/text/Text.class.php</strong><br>
Либо создаём свою функцию, либо идём по минимальному пути и редактируем функцию <em>VideoParser($sText)</em> по аналогии:<br>
<pre class="prettyprint"><code>
                $sText = preg_replace(
            &#39;/&#60;media&#62;(http:\/\/maps\.4x4krasnodar\.ru\/[a-zA-Z0-9_\-]+.+)&#60;\/media&#62;/Ui&#39;,
            &#39; &#60;div style=&#34;margin: 1px; display: inline-block; vertical-align: bottom; width: 640px; height: 480px;&#34; data-url=&#34;$1&#34; class=&#34;bbmedia&#34;&#62;&#60;iframe width=&#34;640&#34; height=&#34;480&#34; frameborder=&#34;0&#34; allowfullscreen=&#34;&#34; mozallowfullscreen=&#34;&#34; webkitallowfullscreen=&#34;&#34; src=&#34;$1?format=iframe&#38;amp;direct&#34; style=&#34;vertical-align: bottom; width: 640px; height: 480px;&#34;&#62;&#60;/iframe&#62;&#60;/div&#62;&#39;,
            $sText);
</code></pre><br>
<br>
<strong>config/jevix.php</strong><br>
Добавляем новый тег в массивы <em>cfgAllowTags</em>, <em>cfgSetTagPreformatted</em>, <em>cfgSetTagNoTypography</em>.<br>
<br>
В итоге кнопка вставляет в заметку аккуратное <pre class="prettyprint"><code>&#60;media&#62;http://...&#60;/media&#62;</code></pre>, а в заметке отображается как-то <a href="http://4x4krasnodar.ru/267.html" rel="nofollow">вот так</a>.]]></description>
					<pubDate>Thu, 08 May 2014 09:44:56 +0400</pubDate>
									</item>
					</channel>
	</rss>
