Как склонировать репозитарий через ssh по нестандартному порту

git clone git+ssh://git-user@git-host.com:1111/rep.git rep
4 ноября 2014, 07:12

Шифрование каталога во FreeBsd при помощи pefs

Страница проекта на github
Качаем последнюю версию, на момент написания статьи это 2011-04-14
fetch https://github.com/downloads/glk/pefs/pefs-2011-04-14.tar.gz
tar -xvf pefs-2011-04-14.tar.gz
cd pefs-2011-04-14
make

Ну что же, как обычно получаем тупую ошибку. Опять разрабы не могут всё сделать как надо
===> sys/modules/pefs (all)
"Makefile", line 11: Malformed conditional (${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64")
"Makefile", line 14: if-less endif
make: fatal errors encountered -- cannot continue
*** Error code 1

Открываем sys/modules/pefs/Makefile, ищем там вот эти строки
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
SRCS+=  pefs_aesni.c
CFLAGS+= -DPEFS_AESNI
.endif

И делаем из нее вот это
#.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
SRCS+=  pefs_aesni.c
CFLAGS+= -DPEFS_AESNI
#.endif

Ну теперь-то всё должно собраться нормально
make install clean
rehash


Когда pefs установлен, можно шифровать каталог.
Для начала создадим его
mkdir /secret
pefs mount /secret /secret
pefs addkey /secret

Вводим пароль (желательно подлиннее)
Шифрованный каталог создан, теперь можно проверить его работу.
Создаем файл
echo 'test' > /secret/file.txt

Проверяем его
cat /secret/file.txt

Теперь размонтируем каталог
pefs unmount /secret

Снова проверим содержимое файла
cat /secret/file.txt

В ответ получаем cat: /secret/file.txt: No such file or directory
Тоесть, не примонтировав каталог и не зная пароля невозможно получить содержимое шифрованного каталога. Это полезно если вы сдаете винт в ремонт на восстановление, либо к вам заглянули маски-шоу :)
При каждом ребуте нужно монтировать каталог и вводить ВЕРНЫЙ пароль, если пароль не верный, то содержимое будет также недоступно.
Монтируем снова
pefs mount /secret /secret
pefs addkey /secret

Если верно ввести пароль, то содержимое будет вновь доступно
cat /secret/file.txt
4 ноября 2014, 07:12

Клонирование объектов в jQuery

Рассмотрим вот такой код
var A = new Object;
var B = A;
A['value'] = 1;
alert(B['value']);

В яваскрипт все объекты передаются по ссылке, поэтому если вы измените свойство объекта A, оно автоматически изменится в объекте B.
Чтобы этого не произошло необходимо клонировать объект
var A = new Object;
var B = jQuery.extend({}, A);

Как клонировать объект на чистом яваскрипт мне, если честно, все равно. Потому что уже врядли можно встретить проект без какого-либо фреймворка.
4 ноября 2014, 07:12

Конфигурация nginx для Yii

Даже на сайте фреймворка yii нет вразумительного конфига для nginx (там много лишнего).
Привожу свой вариант, в связке с php-fpm
server {
        listen       80;
        server_name  your.site.ru;

        charset utf-8;
	root   /usr/local/www/nginx/build;
        index  index.html index.htm index.php;

        location / {
		try_files $uri $uri/ /index.php?$args;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }

	location ~ \w+\.php$ {
                #вот тут лучше заменить на юникс сокет
		fastcgi_pass  127.0.0.1:9000;
		fastcgi_index index.php;
		include fastcgi_params;
		fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;
		fastcgi_param PATH_INFO $fastcgi_script_name;
	}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        location ~ /\.ht {
            deny  all;
        }
		
	location ~ ^/protected/ {
		deny  all;
	}
    }
4 ноября 2014, 07:12

Настройка и установка sphinx поиска для LiveStreet на FreeBsd

Чтобы запустить поиск на LiveStreet нужно сделать следующее
Для начала установим sphinx
cd  /usr/ports/textproc/sphinxsearch
make install clean 
rehash

Теперь идем править ему конфиг /usr/local/etc/sphinx.conf
Для LiveStreet можно взять его в папке install
Сразу даю 3 комментария к коду:
1. prefix_ меняется на префикс, который указывался при установки
2. sql_sock = /var/run/mysqld/mysqld.sock
это путь до сокета mysql, который задается в /etc/my.cnf, если не хочет коннектиться или вы не знаете где он у вас, то просто закоментируйте эту строчку в конфиге
3. не забудьте создать папку где хранить индексы (в конфиге это /var/lib/sphinx)
## Конфигурационный файл Sphinx-а для индексации LiveStreet
 
#######################
#
# Описываем индексы
#
#######################
 
# Источник-родитель для всех остальных источников. Здесь указываются параметры доступа
# к базе данных сайта
source lsParentSource
{
        type            = mysql
        sql_host        = localhost
        sql_user        = user
        sql_pass        = pass
        sql_db          = livestreet
        sql_port        = 3306
        # Для ускорения работы прописываем путь до MySQL-го UNIX-сокета (чтобы
        # операции с БД происходили не через TCP/IP стек сервера)
        sql_sock        = /var/run/mysqld/mysqld.sock
   
       
        mysql_connect_flags     = 32 # 32- включение сжатие при обмене данными с БД
   
        # Включам нужную кодировку соединения и выключаем кеш запросов
        sql_query_pre                   = SET NAMES utf8
        sql_query_pre                   = SET SESSION query_cache_type=OFF    
}
 
# Источник топиков
source topicsSource : lsParentSource
{
        # запрос на получения данных топиков
        sql_query               = \
                SELECT t_fast.topic_id, t_fast.topic_title, UNIX_TIMESTAMP(t_fast.topic_date_add) as topic_date_add, \
                tc.topic_text, t_fast.topic_publish \
                FROM prefix_topic as t_fast, prefix_topic_content AS tc \
                WHERE t_fast.topic_id=tc.topic_id AND t_fast.topic_id>=$start AND t_fast.topic_id<=$end
 
        # запрос для дробления получения топиков на неколько итераций
        sql_query_range         = SELECT MIN(topic_id),MAX(topic_id) FROM prefix_topic
       
        # сколько получать объектов за итерацию
        sql_range_step          = 1000
 
       
        # Указываем булевый атрибут критерия "топик опубликован". Для возможности указания этого критерия при поиске
        sql_attr_uint = topic_publish
 
        # Атрибут даты добавления, типа "время"
        sql_attr_timestamp      = topic_date_add
 
        # мульти-аттрибут "теги топика"
        sql_attr_multi  = uint tag from query; SELECT topic_id, topic_tag_id FROM prefix_topic_tag
 
        sql_ranged_throttle     = 0
}
 
# Источник комментариев
source commentsSource : lsParentSource
{
        sql_query               = \
                        SELECT comment_id, comment_text, UNIX_TIMESTAMP(comment_date) as comment_date, comment_delete \
                        FROM prefix_comment \
                        WHERE target_type='topic' AND comment_id>=$start AND comment_id<=$end AND comment_publish=1
 
        sql_query_range         = SELECT MIN(comment_id),MAX(comment_id) FROM prefix_comment
        sql_range_step          = 5000
 
        sql_attr_uint = comment_delete
        sql_attr_timestamp      = comment_date
}
 
#######################
#
# Описываем индексы
#
#######################
 
index topicsIndex
{
        # Источник, который будет хранить данный индекса
        source                  = topicsSource
        path                    = /var/lib/sphinx/topicIndex
 
        # Тип хранения аттрибутов
        docinfo                 = extern
 
        mlock                   = 0
 
        # Используемые морфологические движки
        morphology = stem_enru
 
        # Кодировака данных из источника    
        charset_type            = utf-8
 
 
        # Из данных источника HTML-код нужно вырезать
        html_strip                              = 1
        html_remove_elements = style, script, code
}
 
# Индекс комментариев
index commentsIndex
{
        source                  = commentsSource
        path                    = /var/lib/sphinx/commentsIndex
 
        docinfo                 = extern
 
        mlock                   = 0
 
        morphology = stem_enru
 
        charset_type            = utf-8
        
        # Из данных источника HTML-код нужно вырезать
        html_strip                              = 1
        html_remove_elements = style, script, code
}
 
#######################
#
# Настройки индексатора
#
#######################
 
 
indexer
{
        # Лимит памяти, который может использавать демон-индексатор
        mem_limit                       = 128M
}
 
#######################
#
# Настройка демона-поисковика
#
#######################
 
searchd
{
        # Адрес, на котором будет прослушиваться порт
        address                         = 127.0.0.1
 
 
        # Ну и собственно номер порта демона searchd
        port                            = 3312
 
        # Лог-файл демона
        log                                     = /var/log/sphinx/searchd.log
 
        # Лог поисковых запросов. Если закомментировать,то логировать поисковые строки не будет
        query_log                       = /var/log/sphinx/query.log
 
        # Время в секундах, которое ждет демон при обмене данными с клиентом. По исчерпании происходит разрыв коннекта
        read_timeout            = 5
 
        # Максимальное количество одновременно-обрабатываемых запросов. 0 означает дофига, а точнее без ограничения
        max_children            = 100
 
        # Файл, в который сохраняется PID-процесса при запуске
        pid_file                        = /var/log/sphinx/searchd.pid
}

Когда конфиг сохранен самое время запустить индексацию и поискового демона
indexer --all
searchd

Теперь осталось только прописать в /etc/crontab задания для периодической индексации топиков и комментов
Топики я поставил на каждый час, а комменты каждые полчаса, а чтобы мудни не было запускаю от рута
0 * * * *   root    /usr/local/bin/indexer --rotate topicsIndex > /dev/null 2>&1
*/30 * * * * root   /usr/local/bin/indexer --rotate commentsIndex > /dev/null 2>&1

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

Основные репозитории в Centos

Сначала надо узнать какая архитектура у системы, делается это через
uname -a

Дальше качаем репозитории в зависимости от архитектуры! (либо i386 либо x86_64)

epel
rpm -ihv http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
rpm -ihv http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm


CentALT
rpm -ihv http://centos.alt.ru/repository/centos/5/i386/centalt-release-5-3.noarch.rpm
rpm -ihv http://centos.alt.ru/repository/centos/5/x86_64/centalt-release-5-3.noarch.rpm


RpmForge (dag)
rpm -ivh http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.i386.rpm
rpm -ivh http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.x86_64.rpm
4 ноября 2014, 07:12

Получение информации о медиа файле (пример с битрейтом mp3) при помощи ExifTool

Очень долго я получал битрейт мп3 через ffmpeg-php. Скажу честно, делает он это паршиво: Некоторые файлы вообще бывает не обрабатывает.
Представляю библиотечку ExifTool
Для начала давайте ее установим, делать это я буду на FreeBsd, но на другие оси действия теже
wget http://www.sno.phy.queensu.ca/~phil/exiftool/Image-ExifTool-8.59.tar.gz
tar -xvf Image-ExifTool-8.59.tar.gz
cd Image-ExifTool-8.59
perl Makefile.PL
make
make test
make install

Ставить нужно самую последнюю версию с сайта, на момент написания статьи это 8.59
Теперь можно пользоваться прямо из php
<?php
$file = 'file.mp3';
$json = array();
exec('/usr/local/bin/exiftool -j \''.escapeshellarg($file).'\'', $json);
$json = json_decode(implode($json));
$json = $json[0];
echo $json->AudioBitrate;
 
//ну и посмотрим какая информация вообще доступна
print_r($json);
?>

stdClass Object
(
    [SourceFile] => /file.mp3
    [ExifToolVersion] => 8.59
    [FileName] => 11001.mp3
    [Directory] => /
    [FileSize] => 3.2 MB
    [FileModifyDate] => 2011:05:25 14:27:58+04:00
    [FilePermissions] => rw-rw-rw-
    [FileType] => MP3
    [MIMEType] => audio/mpeg
    [MPEGAudioVersion] => 1
    [AudioLayer] => 3
    [AudioBitrate] => 128 kbps
    [SampleRate] => 44100
    [ChannelMode] => Stereo
    [MSStereo] => Off
    [IntensityStereo] => Off
    [CopyrightFlag] => 
    [OriginalMedia] => 
    [Emphasis] => None
    [Duration] => 0:03:27 (approx)
)

Получать информацию можно также из видео и графических файлов.
4 ноября 2014, 07:12

Как быть в git если не делается pull на сервере?

А все очень просто
git reset --hard HEAD
git pull

Рекомендации чтобы этого не было: проверьте внимательно .gitignore
4 ноября 2014, 07:12

Подсчет факториала через замыкание в php 5.3

<?php
 
$factorial = function($n) use (&$factorial) {
            if ($n == 0)
                return 1;
 
            return $factorial($n - 1) * $n;
        };
echo $factorial(4); // 1*2*3*4=24
?>
4 ноября 2014, 07:12

Класс для CURL

Встроенная библиотека curl, конечно же, замечательная, но пользоваться ей не всегда удобно, потому что надо писать кучу однотипных строчек.
Предлагаю свой класс для курла, он умеет следующее:
- поддерживается цепочка вызовов
- сразу заданы user-agent и accept (их можно изменить вот так Curl::$ua = '----'; )
- применен паттерн singleton, тоесть возможен только один объект в сценарии
- автоматически разжимает gzip/deflate, при этом запрашивает сжатые данные (это экономит трафик раз в 10)

<?php
echo Curl::init('http://ya.ru')
        ->referer('http://snippets.pp.ru')
        ->cookie('cookie.txt')
        ->exec();
 
class Curl {
 
    static $cookie;
    static $proxy;
    static $ua = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.7) Gecko/20091221 MRA 5.5 (build 02842) Firefox/3.6.7 (.NET CLR 3.5.30729)';
    static $accept = array(
        'Accept' => 'application/xhtml+voice+xml;version=1.2, application/x-xhtml+voice+xml;version=1.2, text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/JPEG,     image/gif, image/x-xbitmap, *\\/*;q=0.1',
        'Accept-Language' => 'ru, en',
        'Accept-Charset' => 'windows-1251, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1',
        'Accept-Encoding' => 'gzip,deflate',
    );
    private $ch; //идентификатор соединения
    protected static $instance; //переменная для singleton
    private $info; //переменная для информации о соеденении
    private $file; //переменная для файла
 
    //функция для инициализации
    public static function init($url='') {
        return (self::$instance === null) ?
                self::$instance = new self($url) :
                self::$instance;
    }
 
    //конструктор
    function __construct($url) {
        $this->ch = curl_init();
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
        if ($url)
            $this->url($url);
        return self::$instance;
    }
 
    //деструктор, закрывает соединение
    function __destruct() {
        if (!is_null(self::$instance))
            $this->close();
    }
 
    //обертка для сохранения файла
    function file($save) {
        curl_setopt($this->ch, CURLOPT_FILE, $this->file = fopen($save, 'w+b'));
        return self::$instance;
    }
 
    //обертка для закрытия соединения
    function close() {
        curl_close($this->ch);
        if (!is_null($this->file)) {
            fclose($this->file);
            $this->file = null;
        }
        return self::$instance = null;
    }
 
    //обертка для задания url
    function url($url) {
        curl_setopt($this->ch, CURLOPT_URL, $url);
        return self::$instance;
    }
 
    //обертка для установки прокси
    function proxy($proxy) {
        curl_setopt($this->ch, CURLOPT_PROXY, $proxy);
        return self::$instance;
    }
 
    //обертка для установки редиректов
    function followlocation($followlocation) {
        curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, $followlocation);
        return self::$instance;
    }
 
    //обертка для установки кукис
    function cookie($cookie) {
        self::$cookie = $cookie;
        if ($cookie) {
            curl_setopt($this->ch, CURLOPT_COOKIEFILE, $cookie);
            curl_setopt($this->ch, CURLOPT_COOKIEJAR, $cookie);
        }
        return self::$instance;
    }
 
    //обертка для установки реферера
    function referer($referer) {
        curl_setopt($this->ch, CURLOPT_REFERER, $referer);
        return self::$instance;
    }
 
    //обертка для получения информации о соединении
    function get_info() {
        return $this->info;
    }
 
    //обертка для задания пост данных $post = array();
    function post($post) {
        $post = http_build_query($post, null, '&');
        curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
        return self::$instance;
    }
 
    //обертка для выполнения соединения
    function exec($close = true) {
        curl_setopt($this->ch, CURLOPT_USERAGENT, self::$ua);
        if (self::$cookie)
            $this->cookie(self::$cookie);
        if (self::$proxy)
            $this->proxy(self::$proxy);
 
        curl_setopt($this->ch, CURLOPT_HTTPHEADER, self::$accept);
        $exec = curl_exec($this->ch);
        $this->info = curl_getinfo($this->ch);
 
        //закрываем соединение если задано
        if ($close)
            $this->close();
 
        return $this->extr($exec);
    }
 
    //функция разжимает gzip/deflate
    protected function extr($s) {
        return (substr($s, 0, 8) == "\x1F\x8B\x08\x00\x00\x00\x00\x00") ? gzinflate(substr($s, 10)) : $s;
    }
 
}
 
?>
4 ноября 2014, 07:12

Обновление дерева портов во FreeBsd

Чтобы поддерживать программное обеспечение в актуальном состоянии нужно иметь последнюю версию портов
portsnap fetch update

Можно даже на крон поставить каждый день утром
0 5 * * * /usr/sbin/portsnap fetch update
4 ноября 2014, 07:12

Домены pp.ru

Кое-как удалось продлить этот домен. Проблема заключалась в том, что он регался не через меня. Но в итоге удалось продлить, так что сниппетс будут доставать вас еще долго.
p.s: nic.ru, вы совсем охуели, барыги чертовы, брать 360 рублей за pp.ru?
4 ноября 2014, 07:12

Установка и настройка NGINX и php-fpm на FreeBsd

Сначала ставим из портов php
cd /usr/ports/lang/php5
make install clean
rehash

При установке вылезет окно, в нем выбираем FPM (да, этот модуль к счатью включен в базовую поставку и уже не надо качать патч как раньше).
Когда php установится ставим рассширения для него (врядли вам нужен голый php)
cd /usr/ports/lang/php5-extensions
make install clean
rehash

Выбираем нужные вам (если что потом можно легко доставить).

Отлично, у нас уставновлен php и рассширения к нему.
Пропишем php-fpm в автозагрузку
echo 'php_fpm_enable="YES"' >> /etc/rc.conf


Теперь самое время поставить веб-сервер nginx
cd /usr/ports/www/nginx
make install clean
rehash

Можно выбрать что-то из дополнительных модулей, но обычно это не надо, хотя в любом случаи можно потом будет пересобрать с ними за пять минут.
Когда nginx установился необходимо тоже прописать его в автозагрузку
echo 'nginx_enable="YES"' >> /etc/rc.conf


Теперь когда у нас есть установленные php и веб сервер можно заняться конфигурацией всего этого добра.
В файле /usr/local/etc/php-fpm.conf заставляем php-fpm работать через unix сокет, а не по tcp, это даст небольшой прирост производительности
;listen = 127.0.0.1:9000
listen = /tmp/php-fpm.sock

Больше в этом файле можно ничего не править

Далее идем в конфигурацию nginx (/usr/local/etc/nginx/nginx.conf)
#user  nobody;
#это число выставляется по количеству ядер вашего процессора
worker_processes  1;

#тут можно настроить логи
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
    #для FreeBsd включайте это
    use kqueue;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    #обозначим, что php-fpm у нас работает через юникс сокет
    #лучше задавать именно так, потому что в будущем можно легко будет сменить этот параметр сразу для всех сайтов 
    upstream fpm {
	server unix:/tmp/php-fpm.sock;
    }

    server {
        listen 80;
        server_name  _; 

        charset utf-8;
        root   /home/www/site;

        location / {
            index  index.php;
        }

        error_page   500 502 503 504  /50x.html;
        
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }

        location ~ \.php$ {
            #здесь задается путь к обработчику php, который мы задали выше в upstream
	    fastcgi_pass fpm;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;
            include        fastcgi_params;			
        }

        #ну и на всякий случай, отдавая дань апаче, скроем его .htaccess
        location ~ /\.ht {
            deny  all;
        }
    }
}


Параметр server_name _ задан так, чтобы nginx обрабатывал любой домен.
Если у вас несколько доменов делайте несколько секций server{} и в server_name указывайте домены и алиасы через пробел.
Параметр root /home/www/site; это аналог DOCUMENT_ROOT, именно в этой директории будет находиться ваш сайт.

Теперь запускаем nginx и php-fpm
service nginx start
service php-fpm start

В /home/www/site создаем index.php со стандартным и пробуем зайти через браузер.
Вопросы засылайте в коментах.
4 ноября 2014, 07:12

Защита от бот спама при помощи javascript

Завелся у меня на одном сайте какой-то заморский спамер. Перманентно шлет пару постов в десять минут.
Ип меняет как перчатки, X_FORWARDED_FOR пустой, юзер агент тоже, разумеется, меняется.
Даже капчу посылает верную. Ну с капчей-то как раз все понятно, есть куча сервисов по ее разгадыванию.
Удалось избавиться от него очень дешевым приемом
<input type="hidden" name="check" value="" id="check" />
<script type="text/javascript">document.getElementById('check').value = 'ok'</script>

Тоесть проставляется ява скриптом value для скрытого инпута, и соответсвенно в скрипте проверка
<?php if ($_POST['check'] != 'ok') die('spam'); ?>

Вот так, дешево и сердито :)
Конечно, этот вариант не даст отправить посты тем, у кого отключен ява скрипт, но даже среди мобильных устройств таких 10% максимум.
4 ноября 2014, 07:12

Использование переменных sql для упорядочивания списков в MYSQL

Имеем вот такую таблицу
id | name | position
1	А	0
2	Б	0
3	В	0
4	Г	0
5	Д	0
6	Е	0
7	Ё	0
8	Ж	0
9	З	0

Ид элемента, название элемента, позиция элемента в списке.
Допустим, надо проставить всем поле position, с учетом какой-то сортировки (например по имени).
Это можно сделать одним запросом, используя sql переменные
UPDATE tbl SET position =(SELECT @a:= @a + 1 from (SELECT @a:= 0) s)
ORDER BY `name`

Результат будет таким
1	А	1
2	Б	2
3	В	3
4	Г	4
5	Д	5
6	Е	6
7	Ё	7
8	Ж	8
9	З	9
4 ноября 2014, 07:12

Обновляем ПО в системе FreeBsd

Все очень просто: чтобы обновить используемый софт устанавливаем утилиту portupgrade
cd /usr/ports/ports-mgmt/portupgrade
make install clean
rehash

А дальше набираем команду и идем пить чай
portupgrade -all
4 ноября 2014, 07:12

Mysql дамп средствами php без shell

Встречаются ситуации, когда по каким-либо причинам у нас не работает команда mysqldump через exec.
Из такой ситуации можно выкрутится следующим кодом:
<?php

/*mysql_connect, mysql_select_db..Подключились к бд*/

function dump_sql($dump_dir)
{
$tables = "SHOW TABLES"; // Получаем список таблиц
$res = mysql_query($tables) or die( "Ошибка при выполнении запроса: ".mysql_error() );
while( $table = mysql_fetch_row($res) )
{
    $fp = fopen( $dump_dir."/".$table[0].".sql", "a" ); // Sql файл таблицы (таблица.sql)
    if ( $fp )
    {
        $query = "TRUNCATE TABLE `".$table[0]."`;\n"; // Чистим таблицу (будет в дампе)
        $un=false;
        fwrite ($fp, $query);
        $rows = 'SELECT * FROM `'.$table[0].'`'; // Получаем данные из таблицы
        $r = mysql_query($rows) or die("Ошибка при выполнении запроса: ".mysql_error());
        while( $row = mysql_fetch_row($r) )
        {
            $query = "";
            foreach ( $row as $field )
            {
                if ( is_null($field) )
                    $field = "NULL";
                else
                    $field = "'".mysql_escape_string( $field )."'";
                if ( $query == "" )
                    $query = $field;
                else
                    $query = $query.', '.$field;
            }
            $query = "INSERT INTO `".$table[0]."` VALUES (".$query.");\n"; // Вставка данных (будет в дампе)
            $un=true;
            fwrite ($fp, $query);
        }
        fclose ($fp);
        if (!$un)
        unlink($dump_dir."/".$table[0].".sql");
    }
}
}

# Вызываем функцию указав папку в которую сохранять дампы
dump_sql('./sql_dumps');
?>


Недостатки метода:
1. Отсутствует create table
2. Избытычность insert into запросов

Преимущества:
1. Работает везде где есть php
2. Не требует знаний shell

п.с.: оба недостатка исправляются прямыми руками кодера =)
4 ноября 2014, 07:12

Shell скрипт для снятия mysql дампов

Я использую этот скрипт для бэкапа баз данных, запускаю по крону в 5 утра
MyUSER="root"       # USERNAME
MyPASS="****"       # PASSWORD
MyHOST="localhost"  # Hostname
 
MYSQL="/usr/local/bin/mysql"
MYSQLDUMP="/usr/local/bin/mysqldump"
GZIP="/usr/bin/gzip"
 
# директория куда сохраняются дампы
DEST="/backups/sql"
 
 
# дата в виде yyyy-mm-dd
NOW="$(/bin/date +"%Y-%m-%d")"
 
# переменная для файла
FILE=""
# переменная со списком баз
DBS=""
 
# получаем список всех баз данных
DBS="$($MYSQL -u $MyUSER -h $MyHOST -p$MyPASS -Bse 'show databases')"
 
for db in $DBS
do
echo "$db"
	FILE="$DEST/$db.$NOW.gz"
	# А делается все через обычный mysqldump, просто автоматизировано :)
        $MYSQLDUMP -u $MyUSER -h $MyHOST -p$MyPASS $db | $GZIP > $FILE
done
4 ноября 2014, 07:12

Определение страны посетителя

Для этой задачи нам понадобится база данных ip адресов по стран. Взять можно тут
http://static.wipmania.com/static/worldip.sql.zip
Распаковываем файл, там нам понадобится worldip.sql
Этот файл занимает 2.6МБ и имеет так называемую жадную вставку, фактически это один sql запрос.
Если честно, у меня еще нигде не получалось залить этот файл за один прием, для этого пришлось писать вот такой скрипт, который разбивает этот дамп на множество запросов.
<?php
 
$dblocation = 'localhost';
$dbname = 'database';
$dbuser = 'user';
$dbpasswd = 'password';
 
$db = new PDO("mysql:host=$dblocation;dbname=$dbname", $dbuser, $dbpasswd,
                array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
 
$db->query("CREATE TABLE IF NOT EXISTS `worldip` (
  `start` int(10) UNSIGNED NOT NULL default '0',
  `end` int(10) UNSIGNED NOT NULL default '0',
  `code` varchar(2) NOT NULL default '',
  PRIMARY KEY (`start`,`end`)
) ENGINE=MyISAM;");
 
$f = fopen('worldip.sql', 'r');
$i = 0;
while ($i < 9) {
    fgets($f);
    $i++;
}
$sql_pre = fgets($f);
 
while (false !== $res = fgets($f)) {
    $sql = $sql_pre . str_replace('),', ')', $res);
    $db->query($sql);
}
?>


Теперь, когда у нас есть база данных, можно получать страну посетителя
<?php
 
$dblocation = 'localhost';
$dbname = 'database';
$dbuser = 'user';
$dbpasswd = 'password';
 
$db = new PDO("mysql:host=$dblocation;dbname=$dbname", $dbuser, $dbpasswd,
                array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
 
//экзаменуемый ip
$ip = '87.250.250.3';
 
$q = $db->prepare("SELECT
worldip.code
FROM
worldip
WHERE INET_ATON(?)
BETWEEN worldip.start AND worldip.`end` LIMIT 1");
$q->execute(array($ip));
$country = $q->fetch();
$country = (isset($country['code'])) ? $country['code'] : '';
echo $country;
?>

Если вы получили в ответе RU, то всё прошло как надо.
4 ноября 2014, 07:12

3D Captcha

<?php
/**
 * 3D Captcha
 * автор: KAndy (http://kandy.habrahabr.ru/)
 * 30.07.08
*/
 
/*
Прочитал на хабрахабре интересный топик
http://habrahabr.ru/blog/php/45463.html
понравилась реализация 
капчи, все четко и ничего лишнего, в стиле ооп
*/
 
$capthca = new Capthca3d(); 
$capthca->render(); 
 
 
class Capthca3d{ 
    const CHARS = 'WEafRTYIPAGHJKXBNM3479j'; 
    protected $hypot = 8; 
    protected $image = null; 
     
    protected $text = ''; 
     
    public function __construct() 
    { 
        $this->time = microtime(true); 
        $this->generateCode(); 
     
    } 
    protected function generateCode() 
    { 
        $chars = self::CHARS; 
        for($i =0; $i<3; $i++){ 
            $this->text .= $chars{ mt_rand(0,22)}; 
        } 
    } 
     
    public function getText() 
    { 
        return $this->text; 
    } 
    protected function getProection($x1,$y1,$z1) 
    { 
        $x = $x1 * $this->hypot;  
        $y = $z1 * $this->hypot; 
        $z = -$y1 * $this->hypot; 
         
        $xx = 0.707106781187;  
        $xy = 0; 
        $xz = -0.707106781187;  
         
        $yx = 0.408248290464;  
        $yy = 0.816496580928;  
        $yz = 0.408248290464; 
         
        $cx = $xx*$x + $xy*$y + $xz*$z; 
        $cy = $yx*$x + $yy*$y + $yz*$z+ 20 * $this->hypot; 
        return array( 
            'x' => $cx, 
            'y' => $cy 
            );  
    } 
     
    function zFunction($x,$y){ 
        $z = imagecolorat($this->image,$y/2,$x/2)>0?2.6:0; 
        if( $z != 0 ){ 
            $z += mt_rand(0,60)/100; 
        } 
        $z += 1.4 * sin(($x+$this->startX)*3.141592654/15)*sin(($y+$this->startY)*3.141592654/15); 
        return $z; 
    } 
    public function render()     
    { 
        $xx =30; 
         $yy =60; 
         
         $this->image = imageCreateTrueColor($yy * $this->hypot  , $xx * $this->hypot); 
         
        $whiteColor = imageColorAllocate($this->image,255,255,255); 
        imageFilledRectangle($this->image,0,0,$yy * $this->hypot  , $xx * $this->hypot,$whiteColor); 
         
        $textColor = imageColorAllocate($this->image,0,0,0); 
        imageString($this->image, 5, 3, 0, $this->text, $textColor); 
         
         
         $this->startX = mt_rand(0,$xx);     
         $this->startY = mt_rand(0,$yy); 
         
         $coordinates = array(); 
          
        for($x = 0; $x < $xx + 1; $x++){ 
            for($y = 0; $y < $yy + 1; $y++){ 
                $coordinates[$x][$y] = $this->getProection($x,$y,$this->zFunction($x,$y)); 
             } 
         } 
          
        for($x = 0; $x < $xx; $x++){ 
            for($y = 0; $y < $yy; $y++){ 
                 $coord = array(); 
                 $coord[] = $coordinates[$x][$y]['x']; 
                 $coord[] = $coordinates[$x][$y]['y']; 
                  
                 $coord[] = $coordinates[$x+1][$y]['x']; 
                 $coord[] = $coordinates[$x+1][$y]['y']; 
                  
                 $coord[] = $coordinates[$x+1][$y+1]['x']; 
                 $coord[] = $coordinates[$x+1][$y+1]['y']; 
                  
                 $coord[] = $coordinates[$x][$y+1]['x']; 
                 $coord[] = $coordinates[$x][$y+1]['y']; 
                 
                $c = (int) ($this->zFunction($x,$y)*32); 
                $linesColor = imageColorAllocate($this->image, $c, $c, $c); 
                imageFilledPolygon($this->image, $coord, 4, $whiteColor); 
                imagePolygon($this->image, $coord, 4, $linesColor); 
             } 
         } 
         
        $textColor = imageColorAllocate($this->image,0,0,0); 
        imageString($this->image, 5, 3, 0, $this->text, $whiteColor); 
        imageString($this->image, 1, 3, 0, (microtime(true)-$this->time), $textColor); 
        header('Content-Type: image/png'); 
         
        imagepng($this->image); 
        imagedestroy($this->image); 
    } 
}
 
?>
4 ноября 2014, 07:12