<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0">
    <channel>
        <title>n3b.ru</title>
        <link>http://n3b.ru</link>
        <description>N3b/home</description>
        <lastBuildDate>Wednesday, 15-Feb-12 00:41:58 MSK</lastBuildDate>

                <item>
            <title>Assetic в Symfony2, меняем урлы ассетов в зависимости от даты дампа</title>
            <link>http://www.n3b.ru/blog/Assetic-v-Symfony2-menyaem-urly-assetov-v-zavisimosti-ot-daty-dampa</link>
            <description>Еще в ноябре я отписал kriswallsmith, что неплохо было бы имена ассетов сделать зависимыми от даты последнего изменения, дабы браузеры  не грузили закешированные js и css. Собственно, он ничего не ответил. Оно и понятно - в контексте генерации имени ассета, он еще ничего не знает о своем содержимом, а генерируется только основываясь на путях ассетов (в пространстве имен Symfony), булеве debug и массиве имен фильтров. И это правильно (сохраняется обратная зависимость при генерации ссылки на дамп без доступа к исходникам ассетов).

Короче, все просто. Last modified доступен в обратном случае, когда генерится ссылка на дамп. Вот там и можно воткнуть пресловутое ?123456789. Найти можно в Symfony\Bundle\AsseticBundle\Templating\StaticAsseticHelper и Symfony\Bundle\AsseticBundle\Templating\DynamicAsseticHelper

в метод getAssetUrl добавил
[CODE]
return $this-&gt;assetsHelper-&gt;getUrl( блаблабла ) . '?' . $asset-&gt;getLastModified();

[/CODE]

Грязно? Да. С правкой фреймворка? К слову, настройкой сервисов вполне можно оверрайдить фреймворковские хелперы при желании, если мне не изменяет память.

UPD.
проверил, точно можно. я оверрайдил хелпер роутера
[CODE]
templating.helper.router:
  class:          MyVerySecretBundle\Templating\Helper\RouterHelper
    arguments:
      router:     '@router'
    tags:
      - { name: templating.helper, alias: router }

[/CODE]

по-моему, можно вообще перегрузить параметры %assetic.helper.dynamic.class% и %assetic.helper.static.class%, задав свои классы, отнаследованные от коробочных.</description>
            <pubDate>Wednesday, 15-Feb-12 00:41:58 MSK</pubDate>
        </item>
                <item>
            <title>Как раздобыть сервисы в шаблонах Symfony2</title>
            <link>http://www.n3b.ru/blog/Как_раздобыть_сервисы_в_шаблонах_Symfony2</link>
            <description>Допустим, вы, как и я, решили использовать сервисы в качестве контролеров. Допустим, вам необходимо использовать один из сервисов в огромном количестве шаблонов. Ярким примером может послужить корзина покупок в e-commerce.

Варианта, по-моему, только 2:
1) Инжектить сервис в переменную шаблона и передавать ее дальше - от шаблона к шаблону. Утомительно, некрасиво, а при изменении структуры и вовсе губительно. Ясен пень, что явный инжект переменных от шаблона к шаблону улучшает контроль и читаемость кода. Но если шаблонов и переменных десятки? Брррр... 
2) Достать сервис прямо в шаблоне! Не так явно, но весьма гибко и быстро. Как минимум, вам не придется перелопачивать тонны кода при изменениях в самом сервисе.

Так вот, касательно сервисов в шаблонах. Напрямую их достать не получится, увы. Тем не менее, их можно вытащить через слой templating helpers.

Итак, нам понадобятся 2 класса. Непосредственно сервис и template helper:
&lt;script src=&quot;https://gist.github.com/1102062.js?file=MyBundle%5CService%5CCatalog.php&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://gist.github.com/1102062.js?file=MyBundle%5CTemplating%5CCatalog&quot;&gt;&lt;/script&gt;

В описании сервисов нашего бандла инжектим сервис каталога в helper:
&lt;script src=&quot;https://gist.github.com/1102062.js?file=services.yml&quot;&gt;&lt;/script&gt;

Ну а теперь очень легко и просто вытаскиваем сервис из helper'a
&lt;script src=&quot;https://gist.github.com/1102062.js?file=template.html.php&quot;&gt;&lt;/script&gt;

UPD. По сути, templating helpers - сами по себе являются сервисами. Доступ к ним во вьюхе регулируется наличием тега name: templating.helper в конфигурации сервисов. Таким образом, во вьюхе можно использовать абсолютно любой сервис, а прослойка хелперов необходима лишь для того, чтобы дать доступ только к конкретным публичным методам сервиса. Т.е. если вы используете сервис и как контролер, и как хелпер во вьюхе, то в шаблонах будут доступны экшны этого контролера, что не есть хорошо.</description>
            <pubDate>Monday, 09-Jan-12 15:05:53 MSK</pubDate>
        </item>
                <item>
            <title>Конфигурационный контейнер Symfony</title>
            <link>http://www.n3b.ru/blog/Konfiguratsionnyy-konteyner-Symfony</link>
            <description>Переписал мини-контейнер.
Зачем он нужен?
- не требуется инжектить ссылку на сервисный контейнер ядра. то бишь, инкапсулируем непосредственно конфиг в мини-контейнер.
- более-менее гибкая работа с ветками конфига, а не flat-лист переменных или стандартный массив из сервисного контейнера.
- данные можно получать через семантический запрос с точечками. как по мне - так чисто визуально приятней, чем ключи массива ^_^
- во вьюхе верстальщикам можно работать только с той веткой конфига, которая была передана в хелпер мини-контейнера.
- к слову, никто не запрещает использовать контейнер как массив, но, опять же, с семантическим запросом.

&lt;a href=&quot;http://github.com/n3b/Symfony2-Light-Configuration-Container&quot;&gt;сорцы и документашка&lt;/a&gt;</description>
            <pubDate>Monday, 09-Jan-12 14:59:34 MSK</pubDate>
        </item>
                <item>
            <title>Парсер html на основе PHP:Tidy и селекторах CSS</title>
            <link>http://www.n3b.ru/blog/Парсер_html_на_основе_PHPTidy_и_селекторах_а_ля_jQuery</link>
            <description>На днях понадобился парсер html. После долгого прочесывания сети ничего толкового не нашел. Из того, что более-менее устраивало - был либо дикий и громоздкий PHP:DOM, либо глючный и прожорливый Simple Html DOM Parser.

В общем, взялся писать свой. Снарядил основными функциями селекции по аналогии с CSS. Работает чрезвычайно шустро и очень мало кушает.

Исходники и документацию можно взять &lt;a href=&quot;https://github.com/n3b/n3bDOMParser&quot;&gt;здесь&lt;/a&gt;


upd: Велосипед.
&lt;a href=&quot;http://code.google.com/p/phpquery/&quot;&gt;http://code.google.com/p/phpquery/&lt;/a&gt;</description>
            <pubDate>Monday, 31-Oct-11 07:01:10 MSK</pubDate>
        </item>
                <item>
            <title>Загрузка файлов в Symfony2, поточный вывод</title>
            <link>http://www.n3b.ru/blog/Zagruzka-faylov-v-Symfony2-potochnyy-vyvod</link>
            <description>Недавно понадобилось организовать обработку и отдачу файла &quot;на лету&quot; в Symfony2. Сам по себе фреймворк из коробки такого не умеет. Для этого необходимо немного расширить класс Response. Сорцы и примеры &lt;a href=&quot;https://github.com/n3b/Symfony2-StreamResponse&quot;&gt;здесь&lt;/a&gt;.</description>
            <pubDate>Tuesday, 25-Oct-11 10:05:10 MSK</pubDate>
        </item>
                <item>
            <title>Symfony2 и кастомные валидаторы</title>
            <link>http://www.n3b.ru/blog/Symfony2_и_кастомные_валидаторы</link>
            <description>В мануалах не нашел. Необходимо было создать и инжектнуть в форму, не связанную с Entity, кастомный валидатор. Пример в данном случае: если не отмечен чекбокс в произвольной форме заказа, то удаляется связанный с объектом Checkout объект Delivery.

Для начала создаем непосредственно валидатор:

&lt;script src=&quot;https://gist.github.com/1067741.js?file=CheckoutDeliveryValidator.php&quot;&gt;&lt;/script&gt;

затем инжектим его в FormBuilder сразу после создания формы:

&lt;script src=&quot;https://gist.github.com/1067741.js?file=CheckoutFullType.php&quot;&gt;&lt;/script&gt;

profit</description>
            <pubDate>Tuesday, 20-Sep-11 03:26:20 MSK</pubDate>
        </item>
                <item>
            <title>Symfony2 динамическое изменение Validator Constraints</title>
            <link>http://www.n3b.ru/blog/Symfony2_динамическое_изменение_Validator_Constraints</link>
            <description>Задача: есть форма, одно из полей которой является обязательным (в данном примере, поле login не должно быть пустым). Необходимо по состоянию чекбокса произвольной родительской формы изменить набор правил для проверки данной сущности.
Обращаю внимание, заранее прописываем 2 группы валидаторов

&lt;script src=&quot;https://gist.github.com/1068357.js?file=CheckoutFullType.php&quot;&gt;&lt;/script&gt;

Дальше - первое, что пришло в голову, добавить сеттер в Symfony\Component\Form, ибо по умолчанию он отсутствует. Установка валидаторов происходит в момент создания формы, а нам необходимо, чтобы многовложенная форма сгенерилась и отдала одно из уже забинденых значений. В нашем случае - чекбокс 'user_save'.
Итак, добавляем сеттер:

&lt;script src=&quot;https://gist.github.com/1068357.js?file=Customer.php&quot;&gt;&lt;/script&gt;

Дальше, создаем свой Event Subscriber - я так думаю, его нужно нацелить на момент до байнда формы и настройки внутренних данных. Событие FormEvents::PRE_BIND.

&lt;script src=&quot;https://gist.github.com/1068357.js?file=Form.php&quot;&gt;&lt;/script&gt;

Ну а теперь - самое простое: привязка подписчика к менеджеру событий:

&lt;script src=&quot;https://gist.github.com/1068357.js?file=PreBindDataSubscriber.php&quot;&gt;&lt;/script&gt;

Пока что все работает, как хотелось. Ищу более красивые варианты.

UPD. есть вариант без нарушения инкапсуляции, но с повторной инициализацией формы. Подробнее &lt;a href=&quot;https://gist.github.com/1068357&quot;&gt;тут&lt;/a&gt; в комментариях.</description>
            <pubDate>Tuesday, 20-Sep-11 03:25:11 MSK</pubDate>
        </item>
                <item>
            <title>Как я устанавливал ось на SSD</title>
            <link>http://www.n3b.ru/blog/Как_я_устанавливал_ось_на_SSD</link>
            <description>Win7 x64
- отключил индексацию диска
- файл подкачки на обычный хард
- установил ramdisk  http://members.fortunecity.com/ramdisk/RAMDisk/ramdriv001.htm , выделил 2 гига, назначил ежечасный сброс образа на обычный хард
- перекинул Chrome на ramdisk, запуск ярлыком с параметрами Z:\Programs\Google\Chrome\Application\chrome.exe --user-data-dir=&quot;Z:\Programs\Google\Chrome\User Data&quot; --disk-cache-size=1 --media-cache-size=1
- переменные среды: temp, tmp - назначил переменную, по умолчанию на рамдиск, если нужен temp более 2гб, переключаю на обычный хард
- реестр:
1) DisablePagingExecutive. Установить параметр DisablePagingExecutive со значением - 1. Это позволит ядру работать непосредственно в памяти (ОЗУ) , а не загружать/размещать различные модули (драйвера итп.) с жесткого диска (файл подкачки). По умолчанию этот параметр выключен - значение: 0. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management]
2) LargeSystemCache. Параметр LargeSystemCache так же необходимо установить со значением - 1. Это заставит систему сохранять данные в памяти вместо страниц памяти на жестком диске.Обеспечивая выделение такого объема памяти, который необходим для совместного использования файлов. [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\LargeSystemCache]

папка Users
- отключил контроль учетных записей UAC
- скопировал Users на другой диск (обязательно с сохранением NTFS прав на папки)
- создал переменную среды %USERS_FOLDER%, указал новый путь к Users
- изменил реестр:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList]
Default = %USERS_FOLDER%\Default
ProfilesDirectory = %USERS_FOLDER%
Public = %USERS_FOLDER%\Public
- создал нового администратора tmp
- ребут, логин под tmp
- переименовал C:\Users в C:\Users.bak
- создал симлинки:
mklink /j c:\Users d:\Users
mklink /j &quot;d:\Users\All Users&quot; c:\ProgramData
mklink /j &quot;d:\Users\Default User&quot; d:\Users\Default
- ребут, логин под собой. Проверил работоспособность, удалил администратора tmp
- включил контроль учетных записей.

Все довольно просто, операция на час максимум (с установкой ОС) - у меня заняла 5 дней. Во-первых, процедура разбавлялась неимоверным количеством алкоголя. Во-вторых, первая установка винды прошла неудачно, загрузчик прописался в MBR SSD, чего мне совсем не хотелось. Пришлось отключить харды через биос и повторить установку. В-третьих, повторная установка винды убила GRUB в MBR главного харда (внезапно ^_^). В-четвертых, восстанавливая GRUB через LIVE CD я (случайно?) запустил новую установку линуха. В результате жутко обиделся, ребутнул комп, отформатировал хард с линухом (отличное решение, а чо ^_^). Так что получил отличный бонус в лице повторной настройки никса и софта.

З.Ы. а теперь сижу и думаю... если кэш и tmp на рамдиске, а папка users на обычном харде, как и была,- нахрена тогда ssd?..

cheers ))</description>
            <pubDate>Tuesday, 09-Aug-11 21:17:45 MSK</pubDate>
        </item>
                <item>
            <title>Конфиг nginx под Symfony2</title>
            <link>http://www.n3b.ru/blog/Конфиг_nginx_под_Symfony2</link>
            <description>[CODE]server {
    listen 80;

    charset utf-8;

    set $index 'index.php';
    index $index;
    root '/path/to/web/folder';
	
    try_files $uri $uri/ /$index;

    location ~ \.php($|/) {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        try_files $uri $uri/ /$index;
        fastcgi_intercept_errors;
    }

    include defaults;
}
[/CODE]
З.Ы. конфиг - говно. Подробно написал &lt;a href=&quot;http://n3b.ru/blog/Еще_немного_о_nginx_и_Symfony2&quot;&gt;тут&lt;/a&gt;</description>
            <pubDate>Friday, 08-Jul-11 20:34:42 MSK</pubDate>
        </item>
                <item>
            <title>UTF8 по умолчанию в MYSQL</title>
            <link>http://www.n3b.ru/blog/UTF8_по_умолчанию_в_MYSQL</link>
            <description>/etc/mysql/my.cnf
[CODE][mysqld]
default-character-set = utf8
default-collation = utf8_bin
init_connect = 'SET NAMES utf8'
skip-character-set-client-handshake
[/CODE]</description>
            <pubDate>Friday, 01-Jul-11 11:14:27 MSK</pubDate>
        </item>
                <item>
            <title>Еще немного о nginx и Symfony2</title>
            <link>http://www.n3b.ru/blog/Еще_немного_о_nginx_и_Symfony2</link>
            <description>В общем, немного помаявшись, я нашел для себя рабочий вариант. Предыдущий, в принципе, годен, но, в некоторых случаях, он не подходит.

Основной проблемой является совместное использование следующих правил:
- используются ЧПУ (path_info)
- используется несколько .php файлов
- обработку ошибок необходимо переадресовывать на .php файл
- естественно, отсутствие 'No input file specified'

Путем довольно большого количества проб и ошибок я максимально упростил конфиг, чтобы отработать простейшую механику. Поскольку я не являюсь гуру nginx'a, мне непонятна проблема следующего правила:
[CODE]location / {
    try_files $uri /index.php;
}
[/CODE]
Выполняю следующие запросы: /index.php, /test.php, index.php/test, test.php/test.
Так вот, работают все запросы, кроме последнего. По неизвестным мне причинам, при использовании в запросе .php файла, отличного от index.php, запрос возвращает 404 (следуя текущему правилу, он переадресует на /index.php). При этом, в $uri содержатся абсолютно верные значения. Пришлось искать другие переменные с именем файла. В общем, вот что я собрал в итоге:
[CODE]listen 80;
server_name example.com
charset utf-8;

set $root /path/to/web;
root $root;

location / {
    try_files $uri @default;
}

location ~ ^/[\w_]+\.php.* {
    try_files $fastcgi_script_name @default;
    include fastcgi.conf;
    fastcgi_split_path_info ^(/[\w_]+\.php)(.*)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
}

location @default {
    include fastcgi.conf;
    fastcgi_param SCRIPT_FILENAME $root/index.php;
}

include defaults;
[/CODE]
Все работает, как ожидалось. Ах, да, не забываем про fastcgi.conf:
[CODE]fastcgi_pass 127.0.0.1:9000;

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
[/CODE]</description>
            <pubDate>Thursday, 30-Jun-11 20:31:27 MSK</pubDate>
        </item>
                <item>
            <title>iptables для веб-сервера</title>
            <link>http://www.n3b.ru/blog/iptables_для_веб_сервера</link>
            <description>/etc/init.d/rc.firewall
[CODE]#!/bin/sh
start_fw()
{
	# Очищаем предыдущие записи
	iptables -F

	# Установка политик по умолчанию
	iptables -P INPUT DROP
	iptables -P FORWARD ACCEPT
	iptables -P OUTPUT ACCEPT

	# Разрешаем локальный интерфейс
	iptables -A INPUT -i lo -j ACCEPT

	# Простая защита от DoS-атаки
	iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT

	# Защита от спуфинга
	iptables -I INPUT -m conntrack --ctstate NEW,INVALID -p tcp --tcp-flags SYN,ACK SYN,ACK -j REJECT --reject-with tcp-reset

	# Защита от попытки открыть входящее соединение TCP не через SYN
	iptables -I INPUT -m conntrack --ctstate NEW -p tcp ! --syn -j DROP

	# Закрываемся от кривого icmp
	iptables -I INPUT -p icmp -f -j DROP

	# REL, ESTB allow
	iptables -A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
	iptables -A INPUT -p udp -m state --state RELATED,ESTABLISHED -j ACCEPT

	# Защита сервера SSH от брутфорса
	iptables -A INPUT -p tcp --syn --dport 22 -m recent --name root --set
	iptables -A INPUT -p tcp --syn --dport 22 -m recent --name root --update --seconds 30 --hitcount 3 -j DROP

	# Разрешаем рабочие порты
	iptables -A INPUT -p tcp --dport 20 -j ACCEPT
	iptables -A INPUT -p tcp --dport 21 -j ACCEPT
	iptables -A INPUT -p tcp --dport 22 -j ACCEPT
	iptables -A INPUT -p tcp --dport 25 -j ACCEPT
	iptables -A INPUT -p udp --sport 53 -j ACCEPT
	iptables -A INPUT -p tcp --dport 80 -j ACCEPT
	iptables -A INPUT -p tcp --dport 110 -j ACCEPT
	iptables -A INPUT -p tcp --dport 143 -j ACCEPT
	iptables -A INPUT -p tcp --dport 443 -j ACCEPT

	# Разрешение главных типов протокола ICMP
	iptables -A INPUT -p icmp --icmp-type 3 -j ACCEPT
	iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
	iptables -A INPUT -p icmp --icmp-type 11 -j ACCEPT
	iptables -A INPUT -p icmp --icmp-type 12 -j ACCEPT
}
stop_fw()
{
	// очищаем
	iptables -F
	iptables -X

	// пропускаем
	iptables -P INPUT ACCEPT
	iptables -P FORWARD ACCEPT
	iptables -P OUTPUT ACCEPT
}

case &quot;$1&quot; in
start)	echo -n &quot;Starting firewall: iptables&quot;
	start_fw
        echo &quot;.&quot; 
	;;
block)	echo -n &quot;Full block&quot;
	iptables -F
	iptables -X
        echo &quot;.&quot;
        ;;
restart) echo -n &quot;Restarting firewall: iptables&quot;
	iptables -F
	iptables -X
	start_fw
        echo &quot;.&quot;
        ;;
stop)	echo -n &quot;Stopping firewall: iptables&quot;
	stop_fw
	echo &quot;.&quot;
	;;
*)	echo &quot;Usage: /etc/init.d/rc.firewall start|stop|restart|block&quot;
        exit 1 
        ;;
esac
exit 0

$ chmod 700 /etc/init.d/rc.firewall
$ update-rc.d /etc/init.d/rc.firewall start 40 S .
[/CODE]</description>
            <pubDate>Monday, 14-Mar-11 02:31:55 MSK</pubDate>
        </item>
            </channel>
</rss>
