Создание jail во FreeBsd

Иногда бывает полезно иметь в работающей системе еще одну или несколько виртуальных систем.
Во FreeBsd средством виртуализации является jail. Примеров применения множество: вы можете создавать jailы на своем сервере для знакомых или клиентов, и это обезопасит вашу систему от их проделок, вы можете поместить (это даже рекомендуется) разные сервисы в отдельные jail, например, mysql в одной системе, apache в другой. Таким образом, взлом mysql сервера ничем не грозит веб серверу.

Управлять jailами я буду при помощи ezjail, конечно, труъ-админы могут катать километры шелл скриптов и управлять всем вручную, но уж извольте..
Для начала установим ezjail
cd /usr/ports/sysutils/ezjail
make install clean
rehash


Теперь проинсталируемся
ezjail-admin install


Если вы еще не собирали мир в вашей системе, то придется это сделать.
Процедура длительная, может занять несколько часов, и потребуется ребут.
cd /usr/scr
make buildworld
make buildkernel
make installkernel
reboot


На сообщения mergemaster можно нажимать enter, конфликтов быть не должно.
mergemaster -p
cd /usr/src
make installworld
mergemaster
reboot


Теперь после сборки мира и 2 ребутов можно проапргейдить наш jail (тоже не быстрое дело)
ejzail-admin update -p -i


Для успешной работы jail ему необходим ip адрес. Внешний ip адрес каждому jail это довольно жирно, поэтому давайте выделим ему локальный ip, например, 192.168.0.11
Давайте добавим этот адрес в нашу сетевую карту em0, а также не забудем разместить запись в /etc/rc.conf чтобы при перезагрузке ничего не потерялось
ifconfig em0 alias 192.168.0.11 netmask 0xffffffff
echo 'ifconfig_em0_alias1="inet 192.168.0.11  netmask 255.255.255.0"' >> /etc/rc.conf


Важным условием выбора адреса является то, чтобы этот ип адрес не использовал ниодин сервис в вашей системе.
Пробуем создать jail
ezjail-admin create -r /usr/home/jails/test test 192.168.0.11


Скорее всего вы получите предупреждения, что ip 192.168.0.11 слушается другими сервисами, типа такого
  This may cause some confusion, here they are:
mysql    mysqld     6923  11 tcp4 6 *:3306                *:*
www      proftpd    1400  0  tcp4 6 *:21                  *:*
root     syslogd    1060  9  udp4   *:514                 *:*

Вам нужно вырубить прослушивание всех ip адресов у этих сервисов (это логично даже с точки зрения безопасности). Как это сделать можете почитать в других статьях на этом сайте.

Когда вы отключите прослушивание ip адреса везде, тогда можно запускать jail.
Но перед запуском сначала добавим его в автозагрузку
echo 'ezjail_enable="YES"' >> /etc/rc.conf


Давайте теперь запустим созданный jail
ezjail-admin start test

Проверим запущенные jails в системе
jls

Если все нормально, то должно выдать нечто такое
# jls
   JID  IP Address      Hostname                      Path
     1  192.168.0.11    test                      /usr/jails/test

Отлично, теперь у нас есть работающий jail!
Прежде чем лезть в него, нужно сразу скопировать файл /etc/resolv.conf чтобы разрешались днс адреса
cp /etc/resolv.conf /usr/jails/test/etc


Также, чтобы пинговаться внутри jail надо добавить пару строк в /etc/sysctl.conf
echo 'security.jail.allow_raw_sockets=1' >> /etc/sysctl.conf
echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf

Перезапустим сервис
service sysctl restart


Все, теперь можно зайти в клетку
jexec 1 csh

*некоторое пояснение: 1 это тот самый JID который показывался командой jls, csh это версия шелла

Первым делом в клетке необходимо создать файл /etc/fstab
touch /etc/fstab
ee /etc/rc.conf

Открываем редактором /etc/rc.conf и пишем туда
network_interfaces=""
rpcbind_enable="NO"
cron_flags="$cron_flags -J 15"
syslogd_flags="-ss"

sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"

sshd_enable="YES"

Проверяем локальный ping
test# ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.010 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.012 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.014 ms

Отлично, пинг работает.

Теперь на счет внешних соединений: Если вы тестируете это на локалке, то внешние соединения из клетки заработают, если же вы делаете это на сервере, то скорее всего пакеты изнутри клетки во внешнюю сеть будут резаться уровнем выше. Для того, чтобы сеть в клетке работала нужно прибегнуть к помощи файрвола.
В качестве файрвола я буду использовать pf. Нужно выйти из клетки перед тем, как настраивать файрвол
test# exit


Оказавшись в основной системе нужно подгрузить pf как модуль ядра
kldload pf
kldstat
echo 'pf_enable="YES"' >> /etc/rc.conf


Создадим файл /etc/pf.conf (xxx.xxx.xxx.xxx это внешний ип адрес вашего сервера), em0 это сетевой интерфейс
В pf.conf пишем
pub="xxx.xxx.xxx.xxx" 

jail_net="192.168.0.11/32"
jail="192.168.0.11"

if="em0"
 
set block-policy return
set skip on lo
scrub in

nat on $if from $jail to !$jail_net -> $pub 
#создали nat

В конце правила не забудьте пустую строку! Теперь наша клетка находится за натом, и для хостера пакеты из нее не будут отличаться от пакетов из основной системы, и он не будет их срезать.

Теперь запустим файрвол и применим эти правила
pfctl -e
pfctl -f /etc/pf.conf


Зайдем еще раз в клетку и пинганем яндекс
jexec 1 csh
test# ping ya.ru
PING ya.ru (87.250.250.3): 56 data bytes
64 bytes from 87.250.250.3: icmp_seq=0 ttl=57 time=65.462 ms
64 bytes from 87.250.250.3: icmp_seq=1 ttl=57 time=76.410 ms

Отлично, теперь сеть работает и у нас есть отдельная виртуальная система.
4 ноября 2014, 07:12

Вопрос про NGINX и переменную в proxy_pass (пофикшено)

location / {
set $h "site.ru";
proxy_pass http://$h;
resolver 8.8.8.8;
}

это работает, запросы /aaa идут на site.ru/aaa

Допустим, надо чуть-чуть поменять путь
location /new/ {
rewrite /new/(.+)$ /$1 break;
proxy_pass http://site.ru;
}

это тоже работает, запросы /new/aaa идут на site.ru/aaa

А вот комбинация 2 вариантов уже не работает
location /new/ {
set $h "site.ru";
rewrite /new/(.+)$ /$1 break;
proxy_pass http://$h;
resolver 8.8.8.8;
}

запросы /new/aaa идут site.ru/new/aaa

Кто знает, как задать хост в переменной и изменить путь?
вопрос на форуме nginx

В nginx начиная с версии 1.0 это пофикшено.
4 ноября 2014, 07:12

Установка и настройка MYSQL 5.5 на FreeBsd 8.2

Сначала ставим весь софт, а именно mysql server и mysql client, делается это очень просто из портов
cd /usr/ports/databases/mysql55-server 
make install clean
rehash


Ставится не так уж быстро, как хотелось бы, поэтому идем пить чай.
Когда сервер и клиент готовы, переходим к инициализации наших баз
cd /usr/local
mysql_install_db


Внимание! Если запустить mysql_install_db не из директории /usr/local то скорее всего будет ошибка.
Этот небольшой нюанс может сэкономит вам пару нервных клеток.

Инициализация создает базу mysql в системе.
Теперь добавим mysql в автозагрузку и запустим его
echo 'mysql_enable="YES"' >> /etc/rc.conf
/usr/local/etc/rc.d/mysql-server start


Если не запустилось смотрим лог ошибок
tail -f /var/db/mysql/`uname -a | awk '{print $2}'`.err


Если mysql заработал можно приступать к настройке.
Первым делом скопируем файл настроек my.cnf
cp /usr/local/share/mysql/my-huge.cnf /etc/my.cnf
/usr/local/etc/rc.d/mysql-server restart

Я выбрал my-huge.cnf потому что это для систем с 1-2Гб памяти.
Посмотрите этот каталог, там есть еще несколько штатных конфигов, подберите для себя оптимальный.
Также можно поковырять в my.cnf и подкрутить там всякое.

Теперь нужно поудалять ненужные базы и юзеров, еще поставить пароль для рута.
mysql -u root
>drop database test;
>UPDATE mysql.user SET Password=PASSWORD('newpwd') WHERE User='root';
>delete from mysql.user where password='';
>FLUSH PRIVILEGES;
>exit;
service mysql-server restart

Отлично, теперь для рута будет стоять пароль newpwd

Теперь давайте создадим базу snippetsdb и юзера snippets
Заходим в mysql рутом
mysql -u root -pnewpwd
>create database snippets;
>grant  usage  on snippetsdb.*  to snippets@localhost  identified by 'пароль';
>grant all privileges on snippetsdb.*  to snippets@localhost;


База и юзер созданы.

Еще можно создать некого юзера admin и разрешить ему управлять базами удаленно
GRANT ALL PRIVILEGES ON *.* TO admin@"%" IDENTIFIED BY 'some_password' WITH GRANT OPTION;

Оставляйте вопросы в комментариях.
4 ноября 2014, 07:12

Установка ffmpeg-php на Centos 5

Внезапно на выделенном сервере стали делаться косячные скриншоты, типа вот таких


Скриншоты создавались через ffmpeg-php. Первая мысль была верной: переустановка ffmpeg-php
[root@www ~]# yum install ffmpeg ffmpeg-devel php-devel 
[root@www ~]# cd /usr/src
[root@www ~]# wget http://switch.dl.sourceforge.net/project/ffmpeg-php/ffmpeg-php/0.6.0/ffmpeg-php-0.6.0.tbz2
[root@www ~]# tar xjf ffmpeg-php-0.6.0.tbz2
[root@www ~]# cd ffmpeg-php-0.6.0
[root@www ~]# phpize
[root@www ~]# ./configure –-enable-shared -–prefix=/usr
[root@www ~]# make

Но тут я встретился с очень интересной ошибкой
/usr/src/ffmpeg-php-0.6.0/ffmpeg_frame.c:421: error: 'PIX_FMT_RGBA32' undeclared (first use in this function)
 make: *** [ffmpeg_frame.lo] Error 1


Оказывается, ффмпег-пхп кривой! Патчим
cd /usr/src/ffmpeg-php-0.6.0
wget http://snippets.pp.ru/data/ffmpeg_frame.c.patch
patch -p0 ffmpeg_frame.c < ffmpeg_frame.c.patch
make clean && make && make install

Если ругается на make и patch то
yum install make patch


Я и без патча решал проблему вот так (но с патчем удобнее)

Открываем файл ffmpeg_frame.c (он в /usr/src/ffmpeg-php-0.6.0/)
Правим там везде PIX_FMT_RGBA32 на PIX_FMT_RGB32

После этого можно устанавливать
[root@www ~]# make
[root@www ~]# make install


Не забываем перезапустить apache (ну или что там у вас) и вписать в /etc/php.ini
extension = ffmpeg.so

После такой свистопляски скриншоты стали отрабатывать нормально.

Разработчики рассширения распиздяи, надо проверять прежде чем выкладывать
p.s зеркало для ffmpeg-php-0.6.0.tbz2
4 ноября 2014, 07:12

301 редирект на php

<?php
header("HTTP/1.1 301 Moved Permanently");
header('Location: http://site.ru');

/*
Еще Вариант header('Location: http://site.ru', true, 301)
*/
28 мая 2011, 14:44

Что делать если apache портит картинки при upload

# Чтобы апаче 1.3.37 (русский апаче) не  портил   картинки  при аплоаде
# надо в .htaccess прописать это
 
CharsetRecodeMultipartForms Off
4 марта 2011, 13:25

Удаление звуковой дорожки из видео

Если вы конвертировали фильмы ффмпегом, то наверняка замечали неприятную особенность: когда у фильма две звуковые дорожки (русская+английская), то 
в сконверченном видео он частенько оставляет только английскую.
Вот так можно решить проблему
 
ffmpeg -i input.avi -map 0:0 -vcodec copy -map 0:1 -acodec copy output.avi
 
в новом файле будет только ПЕРВАЯ звуковая дорожка.
 
Второй способ через mencoder (необходимо его сначала поставить конечно)
 
mencoder -alang ru -ovc copy -oac copy input.avi -o  output.avi
 
У второго способа преимущество в том, что он оставит именно русскую дорожку, а не первую. 
Но для этого русская дорожка должна быть помечена в исходном файле как таковая (за редким исключением это так и есть).
16 февраля 2011, 02:50

Получение почты при помощи imap

<?php
$box = imap_open("{pop.mail.ru/pop3:110}", 'mylo@inbox.ru', 'password');
 
echo '<pre>Писем: ';
echo $count = imap_num_msg($box);
echo "\n\n";
 
$i=1;
while ($i<=$count) {
    $overview = imap_fetch_overview($box, $i);
    echo 'тема: '. imap_utf8($overview[0]->subject);
    echo "\n";
    $body =  imap_body($box, $i);
    $body = imap_qprint($body);
    $body = iconv('windows-1251', 'utf-8', $body);
    echo "$body \n\n***********\n\n";
    $i++;
}
 
imap_close($box);
3 февраля 2011, 02:41

Определение компьютер или мобильное устройство 2

<?php
/*
Регулярочка, конечно, "пацанская", но идет в ногу со временем
*/
$useragent=$_SERVER['HTTP_USER_AGENT'];
if(preg_match('/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i',substr($useragent,0,4)))
header('Location: http://detectmobilebrowser.com/mobile');
?>
3 февраля 2011, 02:40

Установка и синхронизация времени на сервере

Для начала необходимо установить временную зону. 
За это отвечает файл /etc/localtime
Переименуйте его вот так 
 
# mv /etc/localtime /etc/localtime.old
 
Теперь необходимо создать симлинк на файл /etc/localtime с нужной нам временной зоны (пример для Москвовского времени) 
 
# ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime
 
Ну и финальный штрих, синхронизация времени:
 
# ntpdate ntp0.zenon.net
 
(если нету ntpdate, то необходимо установить его)
 
Смотрим в консоле на результат и радуемся
# date
20 января 2011, 02:40

Переадресация с поддомена www через .htaccess

# Очень часто яндекс склеивает ваш сайт с www и без, в итоге получается
# как бы 2 сайта, но неполноценных. Причем, прописка host в robots.txt не помогает.
# Привожу пример коротый 100% работает (это надо писать в .htaccess)
 
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.snippets\.pp\.ru
RewriteRule ^(.*)$ http://snippets.pp.ru/$1 [R=301,L]
 
# Обратите внимание, что код 301 (не 302!), и в условии точки экранируются
# Результат можно проверить, набрав http://www.snippets.pp.ru
25 декабря 2010, 02:39

Zend Guard. Мнимая защита

Zend Guard. Мнимая защита.
 
В последнее время, люди активно "защищают" свои скрипты, кодируя избранные файлы или 
целый проект в Zend Guard. Этими людьми движет желание, чтобы их кодом не пользовались 
как попало, с одной стороны, это понятно. Но с другой стороны, ими движет алчность, они 
не покупают Zend Guard, а качают крякнутый, чтобы потом продавать свои поделки.
 
Расскажу, как можно просто декодировать файл, зашифрованный не последней оф версией, а взломаной.
Для этого существует сервис http://showmycode.com/
 
В поисках закодированных файлов я наткнулся на описание скрипта подсчета переходов на http://wapes.org.ru/
Бинго, база ип как раз закодирована, скачать ее можно по этой ссылке http://wapes.org.ru/xrek/oper.zip
Действительно, файл oper.php в архиве закодирован зендом, давайте его раскодируем, 
потому что базы ип должны быть бесплатными и свободными :)
Грузим этот файл в формочку на http://showmycode.com, вводим простенькую капчу и наслаждаемся результатом
 
<?php
if ( eregi( "oper.php", $PHP_SELF ) )
{
    exit( );
}
$oper = trim( htmlspecialchars( stripslashes( @$_GET['oper'] ) ) );
$oper = @preg_replace( "/[^0-9]/", "", $oper );
if ( $oper != "" )
{
    if ( !( $oper < 0 ) && !( 160 < $oper ) )
    {
        $oper = 0;
    }
}
else
{
    do
    {
        $ip = @$_SERVER['REMOTE_ADDR'];
        $ips = split( "\\.", $ip );
        @$ipnum = @$ips[3] + @$ips[2] * 256 + @$ips[1] * 256 * 256 + @$ips[0] * 256 * 256 * 256;
        $oper = 0;
        $IP101 = array( 1402273792, 1402277888, 3.25123e+009, 3.58203e+009, 3.64763e+009, 2.88676e+009, 1427800064 );
        $IP201 = array( 1402276863, 1402290175, 3.25123e+009, 3.58203e+009, 3.64763e+009, 2.88677e+009, 1427832831 );
        .............. продолжение не пишу
?>
 
Такой "удобный" формат записи ип придумал (скорее всего под укуркой) автор небезызвестного скрипта вапфикс.
А остальные переняли и юзают до сих пор.
 
Почему нельзя было хранить как-то так
array( 
  oper1 => array( 
    array(start, end), 
    array(start, end), 
    array(start, end), 
  ),
  oper2 => array( 
    array(start, end), 
    array(start, end), 
    array(start, end), 
  )  
)
25 декабря 2011, 02:38

Инвертирование rgb цвета

<?php
/**
 * 
 */
function color_inverse($color){
    $color = substr($color, 1); //отрезаем # от цвета
    if (strlen($color) != 6){ return '000000'; } //проверка  на длинну
    $rgb = '';
    for ($x=0; $x<3; $x++){
        $c = 255 - hexdec(substr($color, (2*$x), 2));
        $c = ($c < 0) ? 0 : dechex($c);
        $rgb .= (strlen($c) < 2) ? '0'.$c : $c;
    }
    return '#'.$rgb;
}
 
//возьмем для примера желтый
$color = '#FFFF00';
echo "<div style='height:10%; background-color:$color'></div>";
//посмотрим что получится если его инвертировать
echo "<div style='height:10%; background-color:".color_inverse($color)."'></div>";
 
//на флаг Украины смахивает :))
24 декабря 2010, 02:37

Работа со временем. Получение диаппазонов текущей и прошлой недели

<?php
/**
 * 
 */
 
//понедельник на этой неделе
echo date('d.m.Y', strtotime(date('Y').'W'.date('W')));
echo ' - ';
//воскресенье на этой неделе
echo date('d.m.Y', strtotime(date('Y').'W'.date('W').'-7'));
 
echo '<br />'.PHP_EOL;
 
//прошлую неделю можно получить просто вычитая неделю от предыдущих расчетов    
echo date('d.m.Y', strtotime(date('Y').'W'.date('W').' - 1 week'));
echo ' - ';
echo date('d.m.Y', strtotime(date('Y').'W'.date('W').'-7 - 1 week'));
24 декабря 2010, 02:36

Защита от sql инъекций при помощи pdo_mysql

<?php
/**
 * Защита от sql инъекций при помощи pdo_mysql
 * автор: Nc_Soft
 * 19.12.10
 */

$host = 'localhost'; //хост
$db = 'database_name'; //база данных
$user = 'root'; //юзер
$password = 'password'; //пароль

//соединяемся
$db = new PDO("mysql:host=$host;dbname=$db", $user, $password, 
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));  

//делаем sql запрос на создание таблицы (id|user|time)
$q = $db->prepare("CREATE TABLE IF NOT EXISTS `test` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `user` varchar(20) NOT NULL,
  `time` timestamp NOT NULL default CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; ");

//выполняем запрос
$q->execute();

//теперь давайте добавим запись
$q = $db->prepare("INSERT INTO test SET user=? ");
$q->execute(array('имя1'));

/*
в таблице добавилась запись
обратите внимание, что я не использовал никакие функции для фильтрации
(mysql_real_escape_string и подобные), просто обозначит placeholder куда вставить 
значение через ?,  а потом при execute задал значение массивом
*/

//давайте теперь изменим добавленную запись
//получаем последний добавленный ид
$id = $db->lastInsertId(); 

//запрос на update
$db->prepare("UPDATE test SET user=? WHERE id=? ")->execute(array("новое ' имя", $id));

/*
Обратите внимание, сейчас я воспользовался цепочкой вызовов ->()-> 
чтобы не заводить переменную $q как в примерах выше.
Параметры в массиве должны идти в строгом порядке, как в запросе, 
действительно, будет нелепо перепутать id и name местами ;)
Даже не смотря на то, что в параметре присутствует кавычка запрос выполянется нормально, 
pdo все экранирует самостоятельно.
*/

//если не нравятся ? или хотите изменить порядок, можно заюзать именнованные параметры
$db->prepare("INSERT INTO test SET user=:user ")->execute(array(':user'=>'новый юзер'));
/*
Теперь массив с параметрами не такой безликий как раньше, какой способ задания параметров 
выбрать решайте сами
*/

//Ну и напоследок: как извлекать записи
$q = $db->prepare("SELECT * FROM test");
$q->execute();
$data = $q->fetchAll();

print_r($data);

//подробную информацию о pdo_mysql вы всегда можете найти в гугле
19 декабря 2010, 16:44

Реализация json_encode

<?php
/**
 * Реализация json_encode
 * автор: Alexmuz (http://alexmuz.ru/)
 * 18.09.10
*/

if (!function_exists('json_encode')) {  
    function json_encode($value) 
    {
        if (is_int($value)) {
            return (string)$value;   
        } elseif (is_string($value)) {
	        $value = str_replace(array('\\', '/', '"', "\r", "\n", "\b", "\f", "\t"), 
	                             array('\\\\', '\/', '\"', '\r', '\n', '\b', '\f', '\t'), $value);
	        $convmap = array(0x80, 0xFFFF, 0, 0xFFFF);
	        $result = "";
	        for ($i = mb_strlen($value) - 1; $i >= 0; $i--) {
	            $mb_char = mb_substr($value, $i, 1);
	            if (mb_ereg("&#(\\d+);", mb_encode_numericentity($mb_char, $convmap, "UTF-8"), $match)) {
	                $result = sprintf("\\u%04x", $match[1]) . $result;
	            } else {
	                $result = $mb_char . $result;
	            }
	        }
	        return '"' . $result . '"';                
        } elseif (is_float($value)) {
            return str_replace(",", ".", $value);         
        } elseif (is_null($value)) {
            return 'null';
        } elseif (is_bool($value)) {
            return $value ? 'true' : 'false';
        } elseif (is_array($value)) {
            $with_keys = false;
            $n = count($value);
            for ($i = 0, reset($value); $i < $n; $i++, next($value)) {
                        if (key($value) !== $i) {
			      $with_keys = true;
			      break;
                        }
            }
        } elseif (is_object($value)) {
            $with_keys = true;
        } else {
            return '';
        }
        $result = array();
        if ($with_keys) {
            foreach ($value as $key => $v) {
                $result[] = json_encode((string)$key) . ':' . json_encode($v);    
            }
            return '{' . implode(',', $result) . '}';                
        } else {
            foreach ($value as $key => $v) {
                $result[] = json_encode($v);    
            }
            return '[' . implode(',', $result) . ']';
        }
    } 
}
18 сентября 2010, 22:11

Включаем кэширование через .htaccess

# Включаем кэширование через .htaccess
# Автор: Nc_Soft
# 06.09.10

FileETag MTime Size
<ifmodule mod_expires.c>
<filesmatch ".(jpg|gif|png|css|js)$">
ExpiresActive on
ExpiresDefault "access plus 1 year"
</filesmatch>
</ifmodule>

#можете прописать это на своем хостинге
#например, на jino.ru это ускоряет загрузку сайта
#(отдельный вопрос к хостерам, которые не ставят заголовки кэширования на статику, ну да фиг с ними)
6 сентября 2010, 13:01

Работа с .tar.gz

<?php
/* Я постоянно забываю эти долбаные ключи, поэтому публикую сюда */

exec('tar -cvf file.tar /full/path');  //создать .tar
exec('tar -czvf file.tar.gz /full/path'); //создать .tar.gz (архив)
exec('tar -cjvf file.tar.bz2 /full/path'); //создать .tar.bz2 (архив)

exec('tar -xvf file.tar.gz'); //распаковка
19 июля 2010, 18:43

Фильтрация операторов по ip диаппазонам

<?php
/**
 * Фильтрация операторов по ip диаппазонам
 * автор: Nc_Soft
 * 13.05.10
 */

/*
Часто возникает задача фильтровать трафик в зависимости от оператора.
Можно хранить диаппазоны в базе данных и выбирать оттуда, но для их редактирования
надо либо писать некую админку, либо залазить в phpmyadmin или в подобные вещи.
Предлагаю простенький фильтр, который можно легко и гибко редактировать, 
задавая как диаппазоны, так и одиночные ип адреса. Причем, абсолютно не важен формат записи, 
главное чтобы присутствовал ип адрес. Это позволяет простым копипастом вставлять диаппазоны.
Главное условие - не более 2 ип адресов в строке.
Для примера задаю для мтс и билайна.
*/

//замеряем скорость (об этом ниже)
define('START_TIME',microtime(true));

//функция фильтра, в ней можно редактировать ип адреса
function traf_filter($ip) {
	$opsos = array(
	'beeline' => ' --- ниже можно редактировать ---
	
[217.118.66.0 - 217.118.66.255] //GPRS Core Москва 
[217.118.81.0 - 217.118.81.255] //GPRS Core Ростов-на-Дону
[217.118.78.0 - 217.118.78.255] //GPRS Core Санкт-Петербург
[217.118.79.0 - 217.118.79.255] //GPRS Core Новосибирск
[217.118.91.0 - 217.118.91.255] //GPRS Core Екатеринбург
[217.118.90.0 - 217.118.90.255] //GPRS Core Саратов
[217.118.64.0 - 217.118.64.255] //GPRS Core Хабаровск
[217.118.82.0 - 217.118.82.255] //GPRS Core Ставрополь
[217.118.83.0 - 217.118.83.255] //GPRS Core Челябинск
[217.118.93.0 - 217.118.93.255] //GPRS Core Н.Новгород
[217.118.92.0 - 217.118.92.255] //GPRS Core Череповец
[217.118.95.0 - 217.118.95.255] //GPRS Core Воронеж
[213.252.195.0 - 213.252.195.255] //GPRS Core Калининград
[83.220.227.0 - 83.220.227.255] //GPRS Core Самара
[217.118.89.0 - 217.118.89.255] //GPRS Core Сахалин
[85.115.243.32 - 85.115.243.63] //GPRS Core Иркутск
Beeline (WAP) - [217.118.85.64 - 217.118.85.79]

--- выше можно редактировать ---',

'mts' => '   --- ниже можно редактировать ---

194.54.148.8
213.87.6.8
217.8.235.194
217.8.236.11
217.74.244.13
217.66.145.10
217.66.145.15
213.87.72.73
213.87.72.87
212.92.139.198
195.74.84.32
80.83.238.246
80.83.238.247
80.83.232.0 - 80.83.233.255
80.83.228.0 - 80.83.231.255
80.83.238.0 - 80.83.238.255
80.83.239.1 - 80.83.239.12
84.17.254.0 - 84.17.255.255
95.153.191.0 - 95.153.191.255
195.22.110.0 - 195.22.110.255
195.74.84.36 - 195.74.84.47
195.74.84.74
195.74.84.128 - 195.74.84.223
195.85.238.168 - 195.85.238.223
213.87.8.0 - 213.87.15.255
213.87.64.0 - 213.87.64.63
213.87.64.128 - 213.87.64.255
213.87.76.128 - 213.87.76.255
213.87.77.0 - 213.87.77.255
213.87.80.0 - 213.87.81.255
213.87.82.0 - 213.87.85.255
213.87.86.160 - 213.87.86.195
213.87.87.0 - 213.87.88.255
213.87.89.0 - 213.87.90.255
213.87.92.0 - 213.87.95.255
215.66.146.1 - 215.66.146.32
217.8.225.0 - 217.8.225.255
217.8.226.0 - 217.8.227.255
217.8.228.0 - 217.8.229.255
217.8.230.0 - 217.8.231.255
217.8.232.0 - 217.8.233.255
217.8.234.0 - 217.8.234.255
217.8.236.0 - 217.8.236.255
217.8.239.0 - 217.8.239.255
217.66.146.1-217.66.146.99
217.66.147.0 - 217.66.147.255
217.74.249.0 - 217.74.251.255
217.74.247.128 - 217.74.247.191
217.74.244.128 - 217.74.244.255
217.74.245.0 - 217.74.245.255
217.74.248.0 - 217.74.248.255
217.74.247.192 - 217.74.247.223

--- выше можно редактировать ---	',
);

//числовое представление экзаменуемого ип
$ip = sprintf('%u', ip2long($ip));

//ищем оператора
foreach ($opsos as $oper=>$v) {
	$s = explode("\n", trim($v));

	foreach ($s as $p) {
		$arr = array();
		//ищем ип адреса в строке
		preg_match_all('`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`', $p, $arr);
		if (!count($arr[0])) continue;

		$start = $arr[0][0];
		//если ип адресов в строке 2, то это диаппазон
		$end = isset($arr[0][1]) ? $arr[0][1] : $start;

		//сверка
		if ($ip >= sprintf('%u', ip2long($start)) && $ip <= sprintf('%u', ip2long($end)) ) {
			return $oper;
		}
	}
}

//если ничего не найдено возвращаем пустоту
return ;
}

//применение очень простое
echo traf_filter('195.85.238.213'); //mts

//ну и посмотрим сколько времени пахал скрипт
printf('%.4f sec', microtime(true) - START_TIME); //~0.004 сек

/*
Любители оптимизации, конечно, могут меня пожурить, потому что используются регулярки,
да еще и в цикле. Но ведь всегда можно применить кэширование этого массива + ставить куку тем, 
для кого уже определили оператора.

p.s если вам понравился этот фильтр, то можете меня слегка отблагодарить R167883193132 ;)
*/
13 мая 2010, 16:33

Определение параметров мобильного устройства через яндекс api

<?php 
/**
 * Определение параметров мобильного устройства через яндекс api
 * автор: Nc_Soft
 * 21.04.10
 */

/*
Дока http://api.yandex.ru/detector/doc/dg/concepts/About.xml
но пример для пхп там на данный момент неверный, вот мой вариант
*/

$headers = array();
$hmask = array(
'profile',
'wap-profile',
'x-wap-profile',
'user-agent',
'x-operamini-phone-ua',
);

foreach ($_SERVER as $key => $value) {
	if (strpos($key, "HTTP_") === 0) {
		$field = substr($key, 5);
		$field = strtolower($field);
		$field = str_replace('_', '-', $field);
		if (in_array($field, $hmask)) $headers[$field] = $value;
	}
}

$ch = curl_init('http://phd.yandex.net/detect?'.http_build_query($headers));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
curl_close($ch);
unset($headers);
echo $res;

/*
про ответы сервера можно почитать тут
http://api.yandex.ru/detector/doc/dg/concepts/detector-response.xml

И, пожалуйста, кэшируйте запросы к апи, не долбите яндекс :)
*/
?>
21 апреля 2010, 19:14