- надо ч/з панель переименовывать случайное имя папки с файлами в uploads
- так ли уж надо хранить файлы со случайными именами?
вот если в chrome скачиваешь файл, а у тебя такой уже есть и там же лежит, она новому просто 1-чку в конце имени дописывает
- правильно ли заставлять перезакачивать файл, если он изменился?
а если в подобной ситуации файл не я закачивал? - как я его перезакачаю, и чтобы при этом он остался авторским, а не моим.
- а статистика же пострадает!?! т.е. надо будет пересчитывать или в уме прибавлять.
а ещё можно обсуждение файла загубить... ну и т.д.
Сегодня 10.12.2013, и уже второй месяц с хостингом проблемы, то перестает работать ftp, то просто перестают работать все сайты, причем не только мои а все что хостятся у данного провайдера.
С перебоями все бы не чего в течении максимум часа восстанавливали работа способность площадки. Сегодня же случился полный коллапс, все выходные сидел программировал составлял логику своего веб приложения, написал консольное приложение работающего в кроне, настроил крон, сделал уведомления об ошибках на почту.
Получаю письмо что команда не может быть выполнена, так как фаил не существует, но вчера все работало. Перехожу в панель смотрю что фаил отсутствует, пытаюсь подключиться к ftp получаю ошибку аутентификации. В результате обнаружил что мой аккаунт переместили на другой сервер, пришлось перенастроить ftp, а самое не приятное то, что пришлось восстанавливать логику и консольное приложение. Не стал подымать шума, восстановил критичный участок кода, сделал изменения в базе. Через пару часов снова получаю уведомление об ошибки, посмотрел что все изменения обратно откатились, ну тут я не выдержал написал в тех.поддержку "Заявка:2013121010007651", уже пол дня жду ответа, работать пока не начинаю переживаю что снова будет откат.
Оповещение о переезде на другой сервер и откате не было ни в панели управления ни на почте, ни знаю что у них там твориться, но сейчас просто какой то бардак, буду подыскивать другой хостинг для переброса всех своих сайтов.
Если у вас есть рекомендации посоветуйте где лучше хоститься?
]]>Обзор 30 скриптов галерей: http://www.w3school.ru/blog/web-develop … boxes.html
и ещё 6 flash-галерей: http://www.w3school.ru/blog/web-develop … mages.html
На мой взгляд лучшим плагином для построения фото галерей является fancybox http://fancybox.net/
]]>'users_off'=>array(self::STAT,'SendMailUsers','mail_id','select'=>'count(*)','condition'=>'status=1'),
выходы тут могут быть такие:
1) отвязать отправку уведомлений от самого факта публикации поста - надо сделать
2) уменьшить кол-во отсылаемых писем путём компоновки дайджестов (скажем еженедельных) а не ежесекундных уведомлений при каждом ответе
3) поставить отделённый от постинга механизм уведомлений на отправку очередями-пакетами по расписанию.
Всё это станет возможным только когда Yoorik освободится, ва он сейчас занят. Пользуемся пока так.
]]>Да, с уехавшей пагинацией - тоже мне часто попадается. Но обычно не на известных ресурсах (где за этим следят) а на каких нить старинно-форумных движках, где ничего не затачивали.
Но если новостную не индексировать, то надо делать карты сайта для гугль. а это ещё один модуль, который щас не главный. Поэтому, пока что предлагаю индексировать. пока что...
Во-во - мы пытаемся при помощи ленты сделать общение живее/нагляднее/..., а значит и гугльбот будет чаще посещать нас
]]>давай вернемся к теме. ты считаешь какие ещёфишки реально нужны у нас тут для [ cut ] тега?
и в этой теме отпишешься?
Интересно, что самый ранний тикет о нем, который я увидел, создан еще в 2010 году, и был закрыт разработчиками под предлогом "так и должно быть".
В последнем же тикете, после моего комментария активировалась дискуссия между разработчиками и создателем тикета, в результате которой баг вроде бы признали, но сам тикет пока остается закрытым.
Буду следить за развитием событий :)
]]>В админке на странице Опции для этого появились 2 настройки - "Использовать пул сообщений" и "Размер пакета сообщений".
(Для того, чтобы пул работал, нужно сначала настроить cron, простого включения галочки в админке недостаточно)
]]>За это отвечает скрипт protected/cron.php.
Т.к. он находится в защищенной директории, то извне доступ к нему закрыт. Но это не мешает работать с ним изнутри сервера.
Для того, чтобы скрипт начал выполнять задания, нужно добавить его в список работ cron'а (crontab). Как именно - зависит от вашего хостинга. Например, из командной строки через ssh, либо через web-интерфейс панели управления.
Задание должно выглядеть примерно так:
*/5 * * * * php -f /path/to/root/protected/cron.php 2>&1 > /dev/null
Тут мы запускаем cron.php на выполнение каждые 5 минут.
Для того, чтобы добавить новые задания на выполнение, нет необходимости модифицировать сам protected/cron.php. Достаточно просто указать их в файле настроек protected/config/cron.php.
Что для этого нужно:
Создаем новый класс для вашего задания, наследуем его от класса PeComponent, сохраняем в директории protected/. (Либо, если вы уже добавляли свой класс с заданиями, можете воспользоваться им и добавить ему новый метод)
Пишете метод класса, который будет выполнять нужную работу.
Методу не должно передаваться каких-либо переменных, и он не должен ничего возвращать вызывающему коду.
Если периодичность выполнения работы не совпадает с периодичностью запуска cron.php, добавьте соответствующую проверку. Например, можно хранить дату и время предыдущего запуска в файле в директории cache/ или в базе данных, и сравнивать с ней.
Добавьте правила инициализации объекта вашего класса в protected/config/cron.php, как это описано в этой статье
Там же в protected/config/cron.php добавьте в массив Jobs строку вида:
'jobName' => array('component' => 'objectName', 'method' => 'methodName'),
(С запятой в конце строки)
Здесь нужно заменить jobName на название, которое вы присвоите своему заданию, objectName - на название, которое вы назначили инициализированному объекту вашего класса на предыдущем шаге, methodName - на название метода, который должен выполняться.
Все, после сохранения protected/config/cron.php уже при следующем запуске будет выполнена новая задача.
P.S. Про отладку.
Если при работе вашего кода будет вызвано исключение, то сообщение об ошибке и трассировку (debug trace) можно посмотреть в логе в cache/cron_error.log.
Если при работе кода произошла фатальная ошибка, то искать сообщение нужно в логах сервера, и тут все зависит от настроек вашего хостинга (хотя я надеюсь, что на хостинг вы будете выкладывать уже отлаженный код).
--- Посты
Черновики постов
Смена даты/времени создания поста - (тоже пишется в админ-логи
Очередь публикаций - делаю статью, задаю дату после наст.времени, и она становиться видимой только после наступления даты публикации
Админ-логи - хранят любые модер.действия (что сделал. кто, когда, причина) + уведомление + все могут посомтреть (админ-лента)
Рассылка почты - рассылка пакетами во времени, уведомитель по событиям/модерированиям
Подписка/Избранное - авто+добавление в избранное, уведомление при событиях
поиск,новые темы - отделить новые файлы от тем и ответов (а ответы - не новый материал а обсуждения) Либо выделить цветами, или значками.
--- Пользователи, группы/роли
Rules как на хабре пошагово заставлять читать правила и ставить галки правильно!
New Rules после принятия новых правил, надо чтобы вылазила страница, с которой пока не согласишься - работать с сайтом дальше не можешь.
Виды регистраций - Инвайты, и др.
Передача авторства статьи/фотки и др. - Я опубл. статью Бондаренки, за это он получил инвайт, я после этого передаю авторство его статьи - ему. (модер-действие)
Группы - (перезвать группы в Роли, а группы - теперь будет как в ВК), можно вступать, подписываться?,
- читать нельзя
- читать можно, писать нельзя - для таких - подписка + заявка на вступление
- читать можно, писать можно - для таких - вступить
EPwL - Профиль - интересы-теги, фото в профиле, связка с разделами (т.е. авто раздел - в профиле ссылки на автомобили+борт-журналы.рейтинг; фото-раздел - в профиле ссылки на его оборудование, фото-стаж+ссылки на альбомы и рейтинг, и т.п.)
--- Оформление
bb-коды - список всех которые надо + новых, которые спец-как-обвязки-файлов (флешь-плееры, панорамы и др.) + table
+ отн.размеры шрифтов (загол. и подзагол)
EFU -
1 -
]]>2) лучше не давать возможность скрыть тему в черновик ПОСЛЕ её публикации - правьте в реальном времени и не стесняйтесь факта правки.
]]>Изначально реализовывая паттерн реестр, он совмещает в себе и другие связанные паттерны и функции.
Данное руководство расскажет с точки зрения программиста, как пользоваться классом Pe и настраивать правила инициализации объектов.
Класс Pe был получен от artoodetoo и используется c некоторыми дополнениями.
Оглавление:
Класс Pe определяется в файле protected/pebase.php
Класс статический, т.е. нет необходимости создавать экземпляры класса, для того, чтобы пользоваться его функционалом.
В момент подключения класса (include/require) автоматически производится первичная инициализация - вызывается метод Pe::init(). В этот момент происходит вычисление пути к корню движка (в дальнейшем это значение можно получить при помощи Pe::get('root')), назначение класса Pe как обработчика автозагрузки классов и обработчика исключений.
Класс защищен от повторной инициализации - все последующие вызовы Pe::init() игнорируются.
В абсолютном большинстве случаев вам не придется заботиться о подключении и инициализации класса Pe. Все скрипты движка в начале своего выполнения подключают файл protected/bootstrap.php, в начале которого происходит подключение protected/pebase.php и дальнейшее конфигурирование класса Pe. (Подробнее о конфигурировании читайте ниже.)
Класс Pe осуществляет автозагрузку классов.
Это значит, что для использования какого-либо класса, вам не нужно его предварительно подключать с помощью include/require.
Если файл с классом лежит в директории protected/ и имя файла совпадает с именем класса, записанным всеми маленькими буквами, то Pe автоматически найдет и подключит такой файл.
Например, файл protected/myclass.php:
<?php
class MyClass { ... }
При выполнении кода:
$mc = new MyClass();
если класс с именем MyClass не существует, PHP обращается к классу Pe, чтобы тот обработал автозагрузку (метод Pe::_handleClass()), при этом ему передается имя класса. Pe преобразует это имя так, чтобы оно содержало только строчные буквы, после чего проверяет существование файла protected/myclass.php. Если такой файл существует, он будет подключен. В противном случае выбрасывается исключение.
При возникновении исключения, управление передается методу Pe::handleException(), который делегирует обработку исключения классу ErrorHandler. Класс ErrorHandler является оберткой над модифицированной функцией error() из FluxBB 1.4, и описание этого класса выходит за рамки статьи.
В реестре класса Pe могут храниться именованные данные различной природы (числа, строки, массивы, объекты).
Для ручного помещения данных в реестр используется метод Pe::set(). Первым параметром передается имя, по которому будут доступны данные, вторым - сами данные. Если данные с указанным именем уже существуют в реестре, они будут замещены новыми.
Пример использования:
Pe::set('digit', 42);
Pe::set('string', 'Hello, World!');
Pe::set('list', array(1, 2, 3, 4, 5));
Pe::set('myclass', new MyClass());
На имена хранимых данных не накладывается каких-либо ограничений, но в большинстве случаев удобнее, если они удовлетворяют требованиям PHP по именованию переменных.
Извлечение данных из реестра выполняется методом Pe::get(), которому параметром передается имя извлекаемого ресурса.
Извлечение данных является более сложным процессом:
Если данные с указанным именем существуют в реестре, они извлекаются и возвращаются методом.
Если данных нет, проверяется набор правил инициализации на предмет наличия там правила для указанного имени ресурса. (О правилах читайте ниже). При наличии правил, данные инициализируются, сохраняются в реест с нужным именем и возвращаются методом.
Если 1 и 2 условия не выполняются, метод возвращает null
Пример использования:
$pun_config = Pe::get('pun_config');
Что происходит в этой строке? Предположим, что ранее Pe::get('pun_config') не вызывалось и Pe::set('pun_config', ...) тоже никто не делал. Тогда, в соответствии с текущими настройками движка, происходит следующее:
Класс Pe не находит в реестре записи с именем 'pun_config' и обращается к списку правил.
В списке правил инициализации находится запись, которая указывает, что 'pun_config' можно получить из кэша с помощью класса CacheLoader и его метода getData. Если быть более точным, то там содержится только имя некоторого ресурса, который тоже должен храниться в реестре, и его метод. К какому классу принадлежит ресурс, какого типа данные вернет его метод и откуда эти данные получены, классу Pe неважно.
Класс Pe ищет в реестре объект с именем 'cacheLoader' (так записано в правилах инициализации). Предположим, что не находит.
Класс Pe ищет правила инициализации для объекта 'cacheLoader'. Здесь-то как раз и указано, что этот объект принадлежит классу CacheLoader, а также указано, какие параметры необходимо передать конструктору класса. Объект создается.
В этот момент, где-то между new и ; срабатывает автозагрузка и подключает php-файл с исходным кодом класса CacheLoader.
Созданный объект сохраняется в реестре под именем 'cacheLoader'. При следующем обращении к нему, уже не придется его создавать.
Вызывается метод getData() которому в качестве параметра передается имя того, что нужно извлечь из кэша. Предположим, что конфигурация уже была ранее помещена в кэш. В противном случае внутри метода getData() был бы вызов Pe::get('cacheGenerator')->generateConfigCache(), который извлекает конфиг из базы данных и сохраняет в кэше. (В качестве упражнения, можете построить последовательность действий, которая при этом произошла бы).
Данные о конфигурации сохраняются в реестр под именем 'pun_config' и при следующем обращении будут взяты уже оттуда.
Полученные данные возвращаются методом get() и сохраняются в переменной $pun_config.
Далее будет описано как настроить Pe на выполнение всего этого.
Рассмотренный ранее метод Pe::set() позволяет загружать только один именованный элемент данных, загружаемые данные при этом должны быть уже инициализированы. Но что если мы хотим загрузить сразу большое количество именованных данных или вообще снять с себя необходимость каждый раз вручную инициализировать некоторые из них?
На этот случай в классе Pe предусмотрено конфигурирование реестра. Оно выполняется методом Pe::config(). В качестве параметра этому методу передается массив следующего вида:
array(
'rules' => array( ... ),
'name1' => %value1%,
'name2' => %value2%,
...
'nameN' => %valueN%
)
Где name1, ..., nameN - это произвольные имена, которые вы сами выбираете для ваших данных. Как уже упоминалось выше, на имена не накладывается каких-либо ограничений, но в большинстве случаев желательно, чтобы они удовлетворяли требованиям PHP по именованию переменных. Если вы не планируете использовать эти данные для инициализации других данных или объектов, то подойдут любые символы, которые можно напечатать на клавиатуре. Но в правилах инициализации можно использовать ссылки на другие элементы реестра только если их имена удовлетворяют ограничениям. %value1%, ..., %valueN% - произвольные значения, которые позже будут помещены в реестр.
'rules' - это особый элемент конфигурационного массива, который задает правила для инициализации данных.
Он подробнее будет рассмотрен ниже.
Здесь же отмечу, что сам этот элемент в реестр не помещается. Т.е. Pe::get('rules') вернет null. Если поместить элемент с таким именем в реестр через Pe::set('rules', ...), то это не добавит новых правил для инициализации, а сами данные, передаваемые в метод set(), будут помещены в реестр в том виде, как вы их передали.
Файлы конфигурации движка хранятся в директории protected/config/
Из себя они представляют обычный PHP-файл, единственным предназначением которого является создание и возврат конфигурационного массива, описанного ранее.
Почему я говорю именно "создания", а не, например, "хранения"?. Дело в том, что ничто не мешает нам конструировать такой массив динамически.
Пример из protected/config/main.php:
// {$start} is set in protected/bootstrap.php
'pun_debug' => defined('PUN_DEBUG') ? array('component' => 'punPage', 'method' => 'getPunDebug', 'start' => '{$start}') : null,
'saved_queries' => defined('PUN_SHOW_QUERIES') ? array('component' => 'punPage', 'method' => 'getSavedQueries') : null,
При необходимости, логика создания конфигурационного массива может быть и более сложной.
Файлы конфигурации движка имеют следующую структуру:
<?php
return array(
'rules' => array(
...
),
...
);
А использовать их можно следующим образом:
Pe::config(include(Pe::get('root') . 'protected/config/main.php'));
На данный момент в движке используются только три файла конфигурации:
protected/config/main.php - основные настройки и правила инициализации для движка. Здесь вы найдете 98% настроек и правил используемых при повседневной работе скриптов.
protected/config/config.php - этот файл создается после установки и содержит те же самые данные, что и config.php в FluxBB ветки 1.4. Например, там хранится пароль от базы данных.
protected/config/install.php - версия конфигурации, используемой во время установки движка. После установки можете смело удалить этот файл, он больше не понадобится.
Еще небольшая часть конфигурации задается методом Pe::set() в protected/bootstrap.php. Например, там можно увидеть такие строчки:
// Define standard date/time formats
Pe::set(
'forum_time_formats',
array($pun_config['o_time_format'], 'H:i:s', 'H:i', 'g:i:s a', 'g:i a')
);
Pe::set(
'forum_date_formats',
array($pun_config['o_date_format'], 'Y-m-d', 'Y-d-m', 'd-m-Y', 'm-d-Y', 'M j Y', 'jS M Y')
);
Правила инициализации в файлах конфигурации сгруппированы по их назначению, каждая такая группа подписана.
DataBase section - работа с базой данных.
User section - пользователь и все что с ним связано (cookies, пометка тем прочитанными).
Cache section - работа с кэшем (генерация кэша редко изменяемых, но часто требуемых данных, получение данных из кэша).
Language section - работа с языковыми файлами.
Template section - шаблонизатор и то, что с ним связано.
Parser - парсер.
File upload - класс FileUpload.
Controllers - тут собраны все классы-контроллеры (см. модель MVC).
Несколько правил, которые не подходят под другие категории.
Группа правил, которые в FluxBB ветки 1.4 определялись через if (!defined(...)) define(...); в include/common.php.
В конфигурационных файлах присутствуют также и просто данные. Их не так много, если сравнивать с количеством строк, занятого правилами инициализации.
Например, там определяются такие константные значения, как виды контента (kind), требуемая ревизия базы данных, виды пользователей (админ, модератор, гость и т.д.) и прочее.
Выше мы рассмотрели конфигурирование реестра, где упоминалось о том, как передать правила инициализации данных. Теперь рассмотрим, что же из себя представляют эти данные.
Элемент 'rules' является массивом, структура которого напоминает структуру самого конфигурирующего массива:
Pe::config(array(
'rules' => array(
'name1' => %value1%,
...
'nameK' => %valueK%
),
...
));
name1, ..., nameK - произвольные имена, которые вы задаете для правил. Впоследствии это будут имена элементов данных в реестре. Т.е. правило для Pe::get('pun_config') должно иметь имя 'pun_config', иначе класс Pe не найдет правило и вернет null. %value1%, ..., %valueK% - либо особым образом параметризованная строка, либо массив определенной структуры.
Пример параметризации строки:
'forum_cache_dir' => '{$root}cache/',
На моем компьютере вызов Pe::get('forum_cache_dir'); вернет "/var/www/flux/pe/cache/".
Параметр задается при помощи открывающей фигурной скобки {, имени переменной (знак $ + имя элемента данных в реестре) и закрывающей фигурной скобки }. Это похоже на то, как можно средствами PHP параметризовать строку в двойных кавычках:
$a = 'Hello';
$b = 'World';
$str = "{$a}, {$b}!"; // "Hello, World!"
В нашем же случае кавычки используются одинарные, чтобы не пришлось экранировать символы с особым значением. И сама интерпретация параметров у нас происходит не в момент когда строка объявляется, а намного позже - при первом использовании строки (перед возвращением из Pe::get() или перед передачей в качестве параметра конструктору класса или методу (подробнее см. ниже)).
Параметров в строке может быть несколько.
Если в строке нет ни одного параметра, она возвращается в неизменном виде.
...
'str' => 'Just a string.',
...
Если присутствует только один параметр и кроме параметра нет больше ни одного символа, будет предпринят поиск в реестре по имени параметра, и вместо строки будет возвращены хранящиеся под этим именем данные в том виде, как они хранятся. Т.е. это вполне может быть объект или массив.
...
'rootDir' => '{$root}',
'db' => '{$db}',
...
Сейчас строки вида 'db' => '{$db}' могут показаться бессмысленными, и действительно, вне контекста такая строчка является даже ошибочной. Такой подход в основном использется при описании параметров, передаваемых конструктору класса.
Другая строчка примера - 'rootDir' => '{$root}' - по сути задает псевдоним для элемента данных с именем 'root'.
Если присутствует несколько параметров, либо если помимо единственного параметра в строке есть еще и текст, по именам параметров будет предпринят поиск в реестре и в строку вставлены соответствующие значения. Все эти значения должны быть представимы в виде строки, в противном случае вы с большой долей вероятности получите не тот результат, что ожидали.
...
'a' => 'Hello',
'b' => 'World',
'str' => '{$a}, {$b}!', // 'Hello, World!'
...
Пример правила для инициализации объекта:
'langLoader' => array('class' => 'LangLoader',
'rootDir' => '{$root}',
'pun_user' => '{$pun_user}'),
Вызов Pe::get('langLoader'); вернет инициализированный объект класса LangLoader.
Наверное массив, стоящий справа от 'langLoader' => показался вам очень знакомым. Действительно, он имеет ту же структуру, что и конфигурационный массив, с той только разницей, что "особым" элементом теперь является 'class', который указывает, какой класс нужно использовать. Все остальные элементы будут переданы конструктору класса параметром-массивом. При этом все параметризованные строки в этом массиве будут обработаны в соответствии с правилами, описанными выше.
Если вы пишете собственный класс с нуля, можете получить доступ к этим параметрам (из примера с LangLoader), например, так:
public function __construct(array $params)
{
echo $params['rootDir'] . "\n";
echo ($params['pun_user']['is_guest'] ? 'Гость' : 'Не гость') . "\n";
}
или так:
public function __construct(array $params)
{
extract($params);
echo $rootDir . "\n";
echo ($pun_user['is_guest'] ? "Гость" : "Не гость") . "\n";
}
Если же вы наследуетесь от PeComponent, то его конструктор автоматически сохраняет переданные ему параметры в качестве полей объекта, с именами, совпадающими с ключами в массиве правила инициализации. Вы можете заранее определить для них уровень доступности (в противном случае, они будут объявлены как public):
class MyClass extends PeComponent
{
protected
$rootDir, $pun_user;
public function printVars()
{
var_dump($this->rootDir, $this->pun_user);
}
}
Если обобщить все выше сказанное, то вызов $ll = Pe::get('langLoader'); равносилен следующей конструкции:
require Pe::get('root') . 'protected/langloader.php'; // Не забыли про автозагрузку классов?
$ll = new LangLoader(array(
'rootDir' => Pe::get('root'),
'pun_user' => Pe::get('pun_user')
));
Pe::set('langLoader', $ll);
Вернемся к примеру с CacheLoader и $pun_config (см. выше в описании Pe::get()), вот строчка из protected/config/main.php:
'pun_config' => array('component' => 'cacheLoader', 'method' => 'getData', 'data' => 'config'),
Ключевыми являются элементы 'component' и 'method'. Первый указывает имя объекта в реестре, второй метод этого объекта. Все остальные элементы передаются в виде массива этому методу. Слово 'component' как бы предполагает, что объект принадлежит классу, унаследованному от PeComponent. И на самом деле, все подобные объекты в движке унаследованы от PeComponent. Но использовать объекты любого другого класса не запрещается. В случае, если элемент реестра не является объектом, или у него нет метода с указанным именем, будет выброшено исключение.
В упрощенном виде вызов $pun_config = Pe::get('pun_config'); можно представить следующим образом:
$component = Pe::get('cacheLoader');
$pun_config = $component->getData(array('data' => 'config'));
Pe::set('pun_config', $pun_config);