Привет. Хотел презентовать вам движочек в двадцать строчек под названием PinPIE (Pin: PHP Is Enough), но решил сразу показать свою цмсочку, странную и не для всех. PinCMS Когда мне надоело работая в IDE копипастить код в ModX... Когда мне надоело, что простейшая страничка рендерится 300мс... Когда мне надоело, что редакторы цмсок плодят убогий HTML-код, который один хрен надо редактировать... Одним словом, когда я понял, что CMS в классическом виде, которые позволяют любой дохомузяйке работать и творить контент для веба - это капец, и его пора решать, я за несколько часов родил движочек PinPIE. А после, недолго думая, денька за три, родил и PinCMS. Я её походя долго допиливал, но недавно сел, и допилил усиленно. Основная особенность - хранение страниц в файлах. Еще есть, что допилить, но мне нужна обратная связь. И я обращаюсь к вам, жителям этого форума. Я уже сделал пару сайтов на ней, и доволен результатом. Сейчас сайт, на котором лежит моя картинка в подиписи, хостится на VPS за $10. Если кого приспичит потестировать, то прошу не делать этого раньше двух часов ночи по Москве, и не трахать сервак дольше минуты. Для тех, у кого руки не настолько чешутся, чтобы перепроверять мои результаты, сообщаю: С учетом кеширования, главная рендерится за 4-20мс (на серваке гуляет очень процессорное время), в секунду сервак способен выдать 16-20 страниц. Мой домашний комп выдаёт 450+ страниц в секунду на nginx+phpfpm, 550+ на hhvm. Особенности Держитесь за стулья, сейчас взлетим. - Это не для детей. Если вас устраивает код, который генерит редактор известной CMS; Если вы не знаете, сколько потоков браузуер даёт на один домен и сколько вам надо; Если вы не размещаете css вверху, а js строго внизу; Если вы не хотите использовать систему версий; Если вас устраивает работать в IDE и копипастить код, То это не для вас. Я серьёзно. - Нет админки. Это не совсем CMS, ибо у нее нет админки. Вообще. Совсем. Ни в каком виде. Вы можете написать нужную админку сами. Однако C и M у нее очень удобно реализованы. - Это не CMF, тут нет авторизации, работы с БД и вообще чего-то такого. Однако есть методы для добавления на страницу статик-контента, как то картинки, css и js файлы так, чтобы их можно было вынести на любое число поддоменов для ускорения загрузки страницы параллельными потоками. - Работа с контентом в IDE. Со всеми вытекающими плюшками, как то: скорость, подсветка кода, автодеплой, история версий. - Чанки, как кусочки текста. Сниппеты, как кусочки кода php. К чанкам и сниппетам могут применяться темплейты. - Страницы хранятся в файлах *.php. Чанки и сниппеты - тоже. При каждом обращении проверяется, что кеш моложе файла. В противном случае, перечитывается и рендерится свежая версия. Благодаря системному кешу файлов, скорость проверки даты модификации файла очень высока. Благодаря акселератору, их содержимое и байт-код так же кешируются. Это в сумме даёт чудесное быстродействие. (См. Контент и кеширование) - Исполнение php-кода из специального файла каждый раз, при любом обращении до рендеринга страницы, и после из другого. - Исполнение кода страницы всегда каждый раз при любом запросе к этой странице. Но вы можете разместить только кешируемые сниппеты и чанки на ней, если хотите еще сильнее снизить время выполнения. - Параметры сайта задаются в файле php. - Параметры странцы, такие как темплейт, задаются прямо в файле страницы. - Шаблонизатор по-умолчанию не используется, но вами может быть подключен любимый в любой момент. Контент и кеширование Страницы хранятся в файлах. На страницах может быть размещен любой текст или код php. На страницах можно использовать теги PinCMS, такие как теги чанков, сниппетов, и статик контента. Также есть константы и переменные темплейта. Страницы Страницы хранятся в файлах *.php в папке /pages. При запросе проверяется наличие /pages/$_SERVER[REQUEST_URI].php, и при его наличии происходит инклуд этого файла. Если такого файла нет, проверяется наличие папке с по пути /pages/$_SERVER[REQUEST_URI], и если таковая есть, то происходит инклуд /pages/$_SERVER[REQUEST_URI]/index.php. Если такового нету, будет заинклуден файл /pages/notfound.php. До инклуда страницы происходит инклуд файла /preincludes.php, где можно подключить и проинициализировать свои скрипты: любимую бибилиотеку для работы с БД, авторизацию и прочее. После инклуда файла страницы будет вызван файл /postincludes.php. В данном файле вы можете выполнить некие завершающие действия. В случае, если вы не желаете чтобы запрошенная страница отобразилась, например без авторизации, то просто к примеру делаете так PIN::$document='auth.php', где запрашиваете авторизацию. Будет загружена страница /pages/auth.php вместо запрошенной. Чанки и сниппеты Страница является точкой входа, но не единственным контент-элементом. Так же существуют чанки и сниппеты. Чанки живут в по адресу /chunks/*.php и являются просто кусочками текста, который не исполняется, а просто подставляется на страницу. Сниппеты это кусочки кода, которые будут инклюдены, соответственно исполнены, и с помощью волшебных ob_start() и ob_get_clean() водружены на требуемое место. Они живут в папке /snippets тоже в *.php файлах. Чанки вставляются на страницу с помощью тега Код (Text): [[название чанка]] Сниппеты вставляются на страницу с помощью тега Код (Text): [[$название сниппета]] Допустимы папки и пути в данных тегах. Т.е. вы можете группировать и раскладывать свои сниппеты и чанки по папкам. Пример: Код (Text): [[$tech/checkIP]] Будет подключен файл /snippets/tech/checkIP.php В сниппеты можно передавать параметры а-ля GET, которые будут развёрнуты в переменные перед инклудом сниппета. Пример: Код (Text): [[$comments?year=2014&perpage=20]] Статики На текущий момент существует две группы статик контента: картинки, и css и js файлы. В случае с изображениями, тег Код (Text): [[%img=/images/ololo.png]] и будет заменён на путь Код (Text): http://s3.site.ru/images/ololo.png?time=3b12e65a925fd1f3cc941af128288817 где s3 это один из статик поддоменов для куки-фри запросов и скорости загрузки параллельными потоками, а параметр тайм позволяет не задумываться о борьбе с кешированием картинок на стороне клиента, когда вы их меняете на сайте. Т.е. там где вам нужна картинка, например в темплейте, вы делаете так: Код (Text): <img src="[[%img=/images/ololo.png]]" width="242" height="168" border="0" alt=""> В случае с кодом css или js будет подставлен весь html-тег соответствующего типа. Код (Text): [[%css=css/style.css]] Где css/style.css это путь к файлу. Данный тег будет заменён текстом вида: Код (Text): <link rel='stylesheet' type='text/css' href='http://s3.site.ru/css/min.style.css?time=f284f0759a244fc85aab0570aca01e9a'> где s3 это один из статик поддоменов для куки-фри запросов, time это хеш времени и соли, min - в случае если есть минифайнутая версия. Расскажу подробнее. Рендеринг статик тегов происходит каждый раз при запросе к странице. Один раз после всех темплейтов и прочего. Проверяется наличие списка куки-фри серверов в конфиге сайта, куки у юзера с рандомным смещением по этому списку, и из списка серверов выбирается один из серверов. Для каждого пути к файлу всегда будет один и тот же сервер у данного юзера, но благодаря смещению, это разный сервер для разных юзеров. Таким образом на другой странице данный статик файл юзер возьмёт из своего кеша. Константы Константа это возможность вывести некий текст в этом или ином месте (см. Переменные темплейтов) Пример: Код (Text): [heading[=О сепульках]] Данный текст будет помещен в переменную темплейта heading и может быть выведен в темплейте допустим как заголовок страницы. Темлейты К странице может применяться темплейт. Темплейты живут в /templates/*.php. Внутри темплейта так же могут быть чанки и сниппеты. Темплейт для страницы задается коммандой [[@template=example]] - это применит к данной странице темплейт /templates/example.php. По умолчанию применяется темплейт /templates/default.php, и он должен быть. Для того, чтобы вывести страницу без темплейта, например при ответе json, достаточно сделать PinCMS::$template = false. Переменные темплейта Если вы хотите, чтобы чанк или сниппет или статика или константы выводились в ином месте, достаточно после первой скобки написать слово. И вывод данного тега будет помещен в переменную, и будет подставлен вместо [[*переменная]]. Пример: Код (Text): [keywords[=пицца, кола]] И если в темплейте мы напишем: Код (Text): <head> <keywords="[[*keywords]]"> То кейворды со страницы подставятся в темплейт. Еще пример: Код (Text): [username[!$getUserName]] Привет, [[*username]]! Пример по-сложнее: Код (Text): [bottom[%js=/js/ajaja.js]] тут некий текст [[*bottom]] то это даст нам такой результат Код (Text): тут некий текст <script type='text/javascript' src='http://s4.site.ru/stat/js/min.ajaja.js?time=30c03cd43ee4a5ddb2e7559df94952ee'></script> Переменные шаблонизатора сгруппированы по приоритетам, в зависимости откуда были вызваны. Переменные шаблонизатора являются массивами, содержащими текст всех записей в эту переменную. В случае использования вашего шаблонизатора вы должны самостоятельно подготовить переменные для него. С другой стороны, данный способ хранения позволяет использовать списки, не используя разные имена переменных. Дело за вами. Я тестировал на twig. Для подключения шаблонизатора вы должны указать название вашей функции в файле конфигурации сайта в $pincms['template function']. Напрмер так: Код (Text): $pincms['template function'] = "twigtemplatefunc"; А в файле /preincludes.php разместить свою функцию или инклуд нужного файла. Код для подключения шаблонизатора twig выглядит так: Код (PHP): class twigSingleton { public static $twig = null; } require_once ROOT . '/Twig/Autoloader.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_String(); twigSingleton::$twig = new Twig_Environment($loader); function twigtemplatefunc($tag, $template) { $template = twigSingleton::$twig->render($template, $tag['tvars']); return $template; } В вашу функцию передаётся два параметра. Первый это таг (страница тоже таг) со всем-всем, что мы о нём знаем, включая файлы его детей и переменные темплейта в массиве $tag['tvars'], которые вы можете убивать по мере использования, если вдруг вам такое захочется сделать; и отрендерённый темплейт с тегами [[*tagvar]]. Так же присутствуют теги статиков, которые будут обработаны впоследствии. Функция должна вернуть отрендерённый контент. Неиспользованные переменные будут переданы выше по дереву к родителям, и далее будут передаваться всем потомкам, чтобы быть использованы в других местах. Если тег будет закеширован, то его оставшиеся переменные так же будут закешированы, и впоследствии будут передаваться для использования в других местах. Две переменных на текущий момент заняты. Это [[*content]] и [[*tagcontent]] соотв. для вывода содержимого страницы и содержимого тега в данном месте. Вы должны использовать их в своих темплейтах, если хотите увидеть контент. Кеширование Страницы целиком не кешируются. Страница всегда будет исполнена. Кешируются чанки и сниппеты. Кеширование прозрачное, чтобы никогда не сомневаться. Кешируется всё и всегда, если не задан запрет кеширования данного элемента. Т.е. все чанки и сниппеты на странице кешируются, если запрещено это делать для данного конкретного чанка или сниппета на данной конкретной странице в данном месте. По умолчанию кешируется навсегда, но можно задать время кеширования в секундах. По-умолчанию кешируется. Если написать число перед именем сниппета или чанка - будет закеширован на указанное число секунд. Если поставить восклицательный знак - кешировать запрешено. Код (PHP): [[$snippet]] //Закеширован навечно, пока не обновится файл, не перезагрузится сервер [[100$snippet]] //Закеширован на 100 секунд [[!$snippet]] //Запрещено кешировать, будет исполняться при каждом запросе Кеширование происходит раздельно. Т.е. если данный сниппет выводит случайное число, то в первом случае какое-то случайное число будет закешировано навечно. Во втором случае, число будет обновляться каждые 100 секунд не влияя на первое. В третьем случае, число всегда будет сгенерированно заново. Таким образом вы можете либо кешировать, либо кешировать на время, либо не кешировать каждый отдельный чанк или сниппет. Если рядом с кешируемым сниппетом стоит такой же с запретом кеширования, то первый будет закеширован, а второй - нет. Даже если это один и тот же сниппет. Этим достигается контроль. Кеширование происходит после применения темлпейта. Если чанк или сниппет генерирует внутри себя переменные для темплейта, то они так же будут закешированы. Эти переменные будут видны другим чанкам или сниппетам, если даже чанк или сниппет будет прочитан из кеша. Если изменяется файл чанка, сниппета или их темплейта, или их детей, то они будут отрендерены заново. Т.е. если внутри сниппета, который будет закеширован, есть чанк, а в чанке другой сниппет, а к нему применяется темплейт, и вы поменяли любой из этих файлов - вся эта ветка отрендерится заново. Благодаря этому, кешируется только первый кешируемый родитель. В случае изменения его файла, файлов его детей или их темплейтов - вся ветка рендерится заново. На текущий момент доступно два способа кеширования: мемкеш и на файликах. По моим тестам выходит, что на файликах быстрее, но надо как-то самостоятельно контролировать занимаемое пространство, ибо у меня никакого встроенного механизма для этого нет - это должно происходить по крону или иным способом. Мемкеш же не выходит за пределы отведенной ему памяти и сам выбрасывает старые материалы по мере заполнения новыми (как-то так). Задать тип кеша можно в конфиге: Код (PHP): $pincms['cache type'] = 'filecache'; или CFG::$pincms['cache type'] = 'memcache'; В случае с мемкешем необходимо указать адреса серверов: Код (PHP): $pincms['cache']['servers'] = [ [ 'host' => 'unix:///tmp/memcached.sock', 'port' => 0 ], Также вы можете положить в /pincms/classes/ свой файл с именем cache.class.ВАШЕНАЗВАНИЕ.php. С остальным разберётесь по образу и подобию, если на такое решитесь. Конфиг к сайту ищется по адресу /pin/config/site.ru.php сообразно адресу сайта в настройках вебсервера. При первом запуске вы получите сообщение об ошибке, если такого конфига нет. Из этого сообщения вам станет ясно, где должен быть размещён и как должен называться файл конфигурации. Тестовая версия: http://yadi.sk/d/Hf5DhUisGVivj Нужен фидбэк. Не побойтесь запилить какой-нить сайт на моей CMS, она сделана с любовью.
Обновил сборку. http://yadi.sk/d/Hf5DhUisGVivj Работает из коробки. Теперь не чистая CMS, а тестовый сайт с парой страниц (index.php и notfound.php), и парой тегов: снипеет с рандомом и чанк с текстом. Потом докину еще файлов и тегов для демонстрации. Ожидается, что сайт называется pintest.ru, и соотв. конфиг вы найдёте в /pin/config/. Соотв, содержимое страницы это: Код (PHP): [[alalala]][[$random]][[!$random]]<?php phpinfo(); Первый тег это чанк с текстом, второй тег это кешируемый сниппет с рандомным числом, и третий - некешируемый сниппет с новым числом каждый раз. В конфиге сайта стоит отображать время внизу страницы. можете отключить. PinCMS может показать вам репорт. Строчка с выводом отчета раскоментирована в /postincludes.php. Закомментируйте её для безопасности. В любом случае, чтобы увидеть репорт необходимо указать пароль, заданный в конфиге. Пароль передаётся гет-параметром PINCMSREPORT. Регистр важен. Т.е. если вы хотите увидеть отчет, надо сделать так: Код (Text): http:/pintest.ru/?PINCMSREPORT=pintestpass Добавлено спустя 43 секунды: И да, конечно CMS ожидает, что все запросы идут на индекс. В XXI веке я думаю это очевидно.
скачал, глянул код. не запускал... вопрос: На кого рассчитана эта CMS? кто целевой пользователь - среднестатистический юзер(который фиг разберется что там к чему) или программер(которому избалован возможностями популярных ЦМС, а тут по сути каркас, жесткий роутинг, наметки темплейтов... и всё. что его должно заинтересовать?) ?
Parse error: syntax error, unexpected '[' in ................\domains\pintest.ru\pin\defaults.php on line 27 php 5.3.27 ((( написал бы сразу требования, мол меньше 5.4 не подходить )
а что там такого критичного в коде что такие высокие требования к версии? я кроме массивов [] другого не увидел. если бы я делал для публичного использования - то наоборот старался бы сделать так чтоб завелось даже на 5.2
все верно, там массивы объявляются квадратными скобками Код (PHP): $pin = [ 'pages folder' => rtrim(ROOT . '/pages', '/'), 'page not found' => 'notfound.php', ................
За каким чертом? Вы так говорите, будто пхп свежей версии ещё поискать надо. рассчитано на тех, кто подустал от обилия возможностей и кому чтобы сгонять за пивком хватит и велосипеда. парадигма: пхп достаточно.
Пытаюсь создать новый проект в NetBeans с исходными кодами. Мастер пишет, что проект уже есть. Ок, открываю, как проект. Мастер пишет, что не найден путь для инклудов "../Pin" Может, он и не нужен, посмотрим. Далее прописываю в конфиге Apache новый сайт. И не знаю, куда поместить папку для логов. У меня обычно они рядом с сайтом лежат: в корне проекта папки logs и htdocs (ну и nbproject). Для htdocs обычно прописываю правила обработки папки (.htaccess, например, индексы и прочее). А тут не совсем удобно получается, т.к. nbproject в рабочем каталоге, и это прописано в самом пректе. Не удобно, но ладно, всё решаемо. Запускаю страницу. На ней написано "config for pintest not found at E:\www\pintest\pin\config\pintest.php" Смотрю, что в папке config, а в ней и правда нет такого файла, есть только pintest.ru.php, pinpie.ru.php и pincms.dat.php. Так понимаю, что где-то в конфиге не прописан текущий язык, что не хватает ".ru" в имени файла, который ищется. И где что искать? Код в целом нравится, классы всякие, сеттеры-геттеры, приваты-паблики, порадовали и такие "эксепшены": Код (PHP): ThrowOnTrue(self::$depth > 100, 'Maximum recursion level achieved'); ThrowOnTrue(self::$totaltagsprocessed > 10000, 'ten thousands tags processed. It\'s time to stop.'); Но попадаются такие штучки Код (PHP): return '<link rel=stylesheet type=\'text/css\' href=\'' . implode("'>\n<link rel=stylesheet type='text/css' href='", self::$static_css) . '\'>'; (строка 136 в page.class.php)Я бы хотел видеть аттрибут rel в кавычках: Код (Text): rel="stylesheet" Рассчитано только на PHP >= 5.4 (как уже заметили) и только HTML5 (судя по встроенным тегам). Это так, бегло всё, конечно. Нужно ещё разбираться, как всё работает.
Папку нетбинсовую грохнуть забыл. Поправлю. Добавлено спустя 58 секунд: Я на шторм пересел, поэтому он её считает обычной, сорри. Добавлено спустя 1 минуту 42 секунды: Спасибо за фидбек. Ща всё поправлю и перезалью.
Я понял, почему не находит pintest.php. Сайт у меня локальный назван просто pintest, а не pintest.ru, с которым нашелся бы файл pintest.ru.php И если сайт будет называться pintest.com, то придётся файл переименовывать на pintest.com.php
ООП ради ООП, php 5.4 ради php 5.4? Добавлено спустя 3 минуты 11 секунд: "this" не используется ни разу - это серьезно, или мой поиск по файлам глючит?
Воистину так. там нет ни одно объекта. Это ж по сути чуток интеллектуальный инклудер файлов. Ну там есть как самая сложная структура - массив тегов. А по сути вся работа ложится на регулярки и подстановку текста из файлов или вывода скриптов. Причины для ООП тут просто не нашлось.
Тогда нужно удалить все классы. Ну или хотябы удалить везде public и private, если очень хочется использовать класс, как неймспейс для функций. Пока руки не дошли обновить PHP, запустить и покатать. Самый главный момент - там поддерживается вызов в сниппете чанка, который использует другой чанк и т.д. рекурсивно?
Добрался до компа. Подробно отвечаю. Да. Имя конфига соответствует сереверу из запроса. Соотв. если вы заходите на сайт по адресу http://127.0.0.1 то конфиг должен называться 127.0.0.1.php Вот код, который ищет и читает конфиг: Код (PHP): //Reading file and overwriting defaults $config = __DIR__ . DS . 'config' . DS . basename($_SERVER['SERVER_NAME']) . '.php'; if (file_exists($config)) { include($config); } else { echo 'config for ' . basename($_SERVER['SERVER_NAME']) . ' not found at ' . $config; exit(); //no config } конфиг содержит несколько массивов и переменных. В массивах $pin и $pincms содержатся настройки ядра и цмски. В массиве $databases можно, но не обязательно, держать настройки подключения к бд. В любом виде. Вам их читать, БД в цмс не используется. В массиве $static_servers хранятся серверы статик контента. Я про них писал. Можно не использовать. Массив $conf существует для пользовательских данных. Пишите сюда что хотите. Переменная $showtime булевая. Включает и отключает отображение времени, затраченного на рендер страницы. Доступ к массивам и переменным конфига через CFG::* Пример: Код (PHP): if (CGF::$conf['user setting']) {... Если я правильно понял вопрос, то ответ да. В сообщении YSandro как раз есть проверка на достижение предельной глубины рекурсии. На всяк-всяк. Хотя в пхп есть своя, не хуже.
Удалил папку с нетбинсовым всяким. Обновил раздачу. http://yadi.sk/d/Hf5DhUisGVivj Хочу предупредить по поводу того, что есть в архиве. В архиве предлагается сайт с парой страниц. Если вы имеете свой контент с теми же названиями файлов - то при перезаписи файлами из архива, вы свои потеряете. Поэтому я изначально сделал раздачу без страниц и чанков и прочего. Однако в раздаче присутствуют файлы с добавленым расширением .example, которые являются примерными образцами того, какими должны быть эти файлы (без расширения .example). Т.е. чтобы всё было по-взрослому, и ваши конфиги, контенты и прочие штуки не затирались при обновлении из архива, я предлагаю использовать версию pincms-beta, но это требует понимания и прочтения предыдущего абзаца. Добавлено спустя 3 минуты 41 секунду: Статики потому что объекты не нужны по причине того, что: - эти штуки работают с сущностями, существующими в единственном экземпляре и не требуют создания экземпляра - статики бесплатно глобальны и экономят время и целую строчку на создание переменной с сылкой на синглтон. Усё. Не более того. Я мерял производительность и не заметил разницы с чистыми функциями. Приватные потому что просто их не вылезет лишний раз в подсветке и автоподсказках IDE. Т.е. они приватные чтобы просто не мазолить глаза, если с этой штукой не требуется взаимодействий вовне. С этой точки зрения протектед и приват - разницы нет, а приват и короче и понятнее при прочтении. Добавлено спустя 1 минуту 21 секунду: Издёвки не вижу. Сам размышлял над этими вопросами когда-то. Не уберу. Это решение, а не случайный выбор.
Я рекомендую /protected/log и защитить его от внешнего подглядывания. Добавлено спустя 3 минуты 57 секунд: Исправил
Я еще раз обращаю ваше внимание, что я задавался данными вопросами когда-то, но это решение принято сознательно, после взвешивания плюсов и минусов. Концепции как таковые меня не волнуют. Более того. В жертву простоты принесен некоторый функционал, дабы не возникало ситуаций со сложным или двояким толкованием. Императивом данного поделия является максимальная простота и однозначность прочтения. Добавлено спустя 2 минуты 18 секунд: Про ООП дальше тут viewtopic.php?f=26&t=47239
Игорь, я на своем проекте, в котором чуть более чем 1800 юзеров на данный момент с НГ отказался от 5.2 и добавил 5.4...ты не представляешь сколько говна я выслушал ((( процентов 20 до сих пор на 5.2, хотя я с лета того года в каждой рассылке напоминал что надо на 5.3 переехать...похую мороз (((
ты меньше слушай =) - это раз. Два, ну блин, там уже у тебя какая-то сущность сформировалась. А дома погонять можно любой пхп поставить. А чего они буйствуют? Чего им не нравится? Добавлено спустя 21 секунду: А ты запусти мою поделку-то =)
ты все равно не поверишь ((( у многих хостеров до сих пор 5.2 как основа идет ((( да, запустил ) времени было в обрез, посему тока запустил, ну там phpinfo на echo 'хелоу ворд' поменял ) пока все ) Добавлено спустя 2 минуты 8 секунд: а еще, если ты посмотришь ФАК некоторых хостингов, можно увидеть тему: исправление ошибок популярных скриптов при переходе на 5.3 ((( им проще сидеть на 5.2, меньше вопросов в поддержку
обычно там выпадающий списек, и ты так опачки и выбрал. я делал свою поделку не для детишек, а для тех, кто между хостингом за 10 баксов и VPS за 10 баксов - выбирает второе. Добавлено спустя 36 секунд: ты попробуй запусти. а то вон у исандро не завелась, а я тут сижу в дерёвне на ноуте и у меня всё работает, а пробовать по разным компа и хостингам отсюда мне лениво.