Конвертация БД из CP1251 в UTF8

Конвертацию БД из Win-1251 в UTF8 можно произвести разными способами, но самый быстрый и простой — использование SQL-запроса, приведенного ниже.

При помощи этого запроса, можно конвертировать таблицу базы данных в любую, доступную в MySQL кодировку. Но что делать, если таблиц 100, 200 или больше, и все таблицы необходимо перекодировать в UTF8 из Win-1251? Для решения этой проблемы, можно отправить в MySQL запрос, который сгенерирует необходимые SQL-запросы для всех таблиц БД. При использовании PHPMyAdmin останется только скопировать результаты и запустить их как SQL-запрос:

Этот запрос будет работать в MySQL версии 5 и выше. My_DB_for_convert — следует заменить на имя БД, таблицы в которой необходимо конвертировать в UTF-8.

utf8_general_ci или utf8_unicode_ci

utf8_general_ci и utf8_unicode_ci отличаются только скоростью работы и порядком сортировки. Поскольку utf8_general_ci работает быстрее — это и есть предпочтительный выбор. Подробнее, про отличия utf8_general_ci и utf8_unicode_ci можно прочитать в официальной документации MySQL. В случаее необходимости, способом описанным выше, можно будет изменить подкодировку UTF8 c utf8_general_ci на utf8_unicode_ci.

Старт проекта на Django

Прежде всего убедитесь, что у вас подключена услуга «Поддержка Python + Django». На время разработки вам также часто будет нужен доступ по SSH, поэтому перед созданием нового Django-проекта подключите и услугу «Поддержка SSH». Если в качестве базы данных вы будете использовать MySQL, соответствующая услуга также должна быть подключена.

  1. Подключитесь к серверу по SSH и создайте и активируйте виртуальное окружение Python (если вы создаете не первый проект и в качестве виртуального окружения хотите использовать уже существующее, пропустите этот и следующие два шага). Введите команды:


    В результате будет создана папка virtualenv/MyEnv. Вместо MyEnv вы можете выбрать и любое другое имя виртуального окружения.
  2. В рамках виртуального окружения установите свежую версию Django:pip 

    Можно установить и любую другую версию. Например, 1.0:

    Таким же образом можно установить и любые другие модули Python.
  3. Создайте папку, где будут располагаться ваши проекты. Эта папка должна находиться вне DOCUMENT_ROOT, то есть вне папок вида domains/имя_домена. Лучшим вариантом будет создать папку django рядом с директорией domains:
  4. Перейдите в папку с проектами и создайте новый проект:

    В результате будет создана папка имя_проекта со стандартным шаблоном Django-проекта.
  5. Откройте файл settings.py и измените в нем значения необходимых переменных. В качестве значения переменной STATIC_ROOT укажите

    добавив в самое начало файла строку

    Внимание! Если вы будете использовать команду syncdb через SSH, то при использовании MySQL в качестве движка баз данных в поле HOST словаря DATABASES[‘default’] обязательно нужно указать IP 127.0.0.1. Подробнее об этом здесь.

    Более подробную информацию о переменных, доступных для редактирования в settings.py, можно найти в документации Django.

  6. Если вы будете использовать mod_wsgi (предпочтительный вариант):

    В директории домена, на котором будет находиться ваш проект (domains/имя_домена) создайте файл django.wsgi и поместите в него такие строки:

    Примечание. Обратите также внимание на пятую и шестую строки этого кода: если вы в своих проектах обычно не используете имя проекта внутри оператора import (например,«from имя_приложения.models import *», а не «from имя_проекта.имя_приложения.models import *» в файле views.py), то указывать имя проекта в пятой строке нужно два раза, а во второй, наоборот, не нужно:

    Вернитесь к этому примечанию, если будете получать ошибки вида «ImportError: No module named…»

    Затем создайте в той же папке еще один файл — .htaccess — и поместите в него следующие директивы:

  7. Если вы будете использовать mod_python (не рекомендуется):

    В папке с проектами (django) создайте файл modpython_virtualenv.py с таким содержимым внутри:

    В директории домена, на котором будет находиться ваш проект (domains/имя_домена) создайте файл .htaccess и поместите в него такие строки:

    Примечание. Здесь и далее X в имени директории usersX может быть целым числом (1, 2, …) или вообще отсутствовать. Точное значение для вашего аккаунта уточняйте в разделе «Техподдержка / Техническая информация» контрольной панели аккаунта (смотрите значение параметра «Домашняя директория»).

    Позже, когда проект будет запускаться в публичную эксплуатацию, не забудьте поменять значения директив PythonDebug и PythonAutoReload на Off — это предотвратит демонстрацию отладочной информации об ошибках всем посетителям и несколько ускорит работу сайта.

    Примечание. Обратите также внимание на директивы SetEnv и PythonPath: если вы в своих проектах обычно не используете имя проекта внутри оператора import (например,«from имя_приложения.models import *», а не «from имя_проекта.имя_приложения.models import *» в файле views.py), то указывать имя проекта в директиве SetEnv не нужно, а в PythonPath, наоборот, нужно два раза:

    Кроме того, поместите файл modpython_virtualenv.py внутрь папки проекта.

    Вернитесь к этому примечанию, если будете получать ошибки вида «ImportError: No module named…»

    Далее, во всех папках в директории домена, в которых будут содержаться статические файлы (например, static), нужно также создать по файлу .htaccess с такой строкой внутри:

     

На этом установка проекта завершена. Теперь вы можете создавать приложения и приступать к разработке.

Если же в результате выполнения этих действий получаете в браузере ошибку 500, загляните в раздел «Статистика / Лог-файлы».

Безопасный метод авторизации на PHP

Давайте посмотрим вокруг: форумы, интернет магазины, гостевые книги и т.д. используют регистрацию и последующую авторизацию пользователей. Можно даже сказать, что это почти необходимая функция каждого сайта (только если это не домашняя страничка Васи Пупкина или не визитная карточка, какой-нибудь небольшой компании). Сегодня я хочу поделиться со всеми новичками информацией, о том, как лучше это все реализовать.

1. Модель (клиент) 
Регистрация
— логин (a-z0-9)
— пароль
Вход
— логин
— пароль
Cookie
— уникальный идентификатор юзера
— хэш
Модель (сервер) MySQL
Таблица users
user_id (int(11))
user_login (Varchar(30))
user_password (varchar(32))
user_hash (varchar(32))
user_ip (int(10)) по умолчанию 0При регистрации в базу данных записываеться логин пользователя и пароль(в двойном md5 шифровании)

При авторизация, сравниваеться логин и пароль, если они верны, то генерируеться случайная строка, которая хешируеться и добавляеться в БД в строку user_hash. Также записываеться IP адрес пользователя(но это у нас будет опциональным, так как кто-то сидит через Proxy, а у кого-то IP динамический… тут уже пользователь сам будет выбирать безопасность или удобство). В куки пользователя мы записываем его уникальный индетификатор и сгенерированный hash.

Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?
1. Из-за невнимательности программиста, во всей системе могут быть дырки, воспользовавшийсь этими дырками, злоумышленик может вытащить хеш пароля из БД и подставить его в свои куки, тем самым получить доступ к закрытым данным. В нашем же случае, двойной хеш пароля не чем не сможет помочь хакеру, так как расшифровать он его не сможет(теоретически это возможно, но на это он потратит не один месяц, а может быть и год) а воспользоваться этим хешем ему негде, ведь у нас при авторизации свой уникальный хеш прикрепленный к IP пользователя.
2. Если злоумышленик вытащит трояном у пользователя уникальный хеш, воспользовать им он также не сможет(разве если только, пользователь решил принебречь своей безопастностью и выключил привязку к IP при авторизации).

2. Практика
--
— Структура таблицы users

CREATE TABLE users (
user_id int(11) unsigned NOT NULL auto_increment,
user_login varchar(30) NOT NULL,
user_password varchar(32) NOT NULL,
user_hash varchar(32) NOT NULL,
user_ip int(10) unsigned NOT NULL default '0',
PRIMARY KEY (user_id)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;

register.php 
<?
// Страница регситрации нового пользователя

# Соединямся с БД
mysql_connect(«localhost»«myhost»«myhost»);
mysql_select_db(«testtable»);

if(isset($_POST[‘submit’]))
{
$err = array();

# проверям логин
if(!preg_match(«/^[a-zA-Z0-9]+$/»,$_POST[‘login’]))
{
$err[] = «Логин может состоять только из букв английского алфавита и цифр»;
}

if(strlen($_POST[‘login’]) < or strlen($_POST[‘login’]) > 30)
{
$err[] = «Логин должен быть не меньше 3-х символов и не больше 30»;
}

# проверяем, не сущестует ли пользователя с таким именем
$query mysql_query(«SELECT COUNT(user_id) FROM users WHERE user_login='».mysql_real_escape_string($_POST[‘login’]).«‘»);
if(
mysql_result($query0) > 0)
{
$err[] = «Пользователь с таким логином уже существует в базе данных»;
}

# Если нет ошибок, то добавляем в БД нового пользователя
if(count($err) == 0)
{

$login $_POST[‘login’];

# Убераем лишние пробелы и делаем двойное шифрование
$password md5(md5(trim($_POST[‘password’])));

mysql_query(«INSERT INTO users SET user_login='».$login.«‘, user_password='».$password.«‘»);
header(«Location: login.php»); exit();
}
else
{
print 
«<b>При регистрации произошли следующие ошибки:</b><br>»;
foreach(
$err AS $error)
{
print 
$error.«<br>»;
}
}
}
?>

<form method=»POST»>
Логин <input name=»login» type=»text»><br>
Пароль <input name=»password» type=»password»><br>
<input name=»submit» type=»submit» value=»Зарегистрироваться»>
</form>

login.php

<?
// Страница авторизации

# Функция для генерации случайной строки
function generateCode($length=6) {
$chars «abcdefghijklmnopqrstuvwxyzABCDEFGHI JKLMNOPRQSTUVWXYZ0123456789»;
$code «»;
$clen strlen($chars) — 1;  
while (strlen($code) < $length) {
$code .= $chars[mt_rand(0,$clen)];  
}
return 
$code;
}

# Соединямся с БД
mysql_connect(«localhost»«myhost»«myhost»);
mysql_select_db(«testtable»);

if(isset($_POST[‘submit’]))
{
# Вытаскиваем из БД запись, у которой логин равняеться введенному
$query mysql_query(«SELECT user_id, user_password FROM users WHERE user_login='».mysql_real_escape_string($_POST[‘login’]).«‘ LIMIT 1»);
$data mysql_fetch_assoc($query);

# Соавниваем пароли
if($data[‘user_password’] === md5(md5($_POST[‘password’])))
{
# Генерируем случайное число и шифруем его
$hash md5(generateCode(10));

if(!@$_POST[‘not_attach_ip’])
{
# Если пользователя выбрал привязку к IP
# Переводим IP в строку
$insip «, user_ip=INET_ATON(‘».$_SERVER[‘REMOTE_ADDR’].«‘)»;
}

# Записываем в БД новый хеш авторизации и IP
mysql_query(«UPDATE users SET user_hash='».$hash.«‘ «.$insip.» WHERE user_id='».$data[‘user_id’].«‘»);

# Ставим куки
setcookie(«id»$data[‘user_id’], time()+60*60*24*30);
setcookie(«hash»$hashtime()+60*60*24*30);

# Переадресовываем браузер на страницу проверки нашего скрипта
header(«Location: check.php»); exit();
}
else
{
print 
«Вы ввели неправильный логин/пароль»;
}
}
?>
<form method=»POST»>
Логин <input name=»login» type=»text»><br>
Пароль <input name=»password» type=»password»><br>
Не прикреплять к IP(не безопасно) <input type=»checkbox» name=»not_attach_ip»><br>
<input name=»submit» type=»submit» value=»Войти»>
</form>

check.php

<?
// Скрипт проверки

# Соединямся с БД
mysql_connect(«localhost»«myhost»«myhost»);
mysql_select_db(«testtable»);

if (isset($_COOKIE[‘id’]) and isset($_COOKIE[‘hash’]))
{
$query mysql_query(«SELECT *,INET_NTOA(user_ip) FROM users WHERE user_id = ‘».intval($_COOKIE[‘id’]).«‘ LIMIT 1»);
$userdata mysql_fetch_assoc($query);

if(($userdata[‘user_hash’] !== $_COOKIE[‘hash’]) or ($userdata[‘user_id’] !== $_COOKIE[‘id’])
or ((
$userdata[‘user_ip’] !== $_SERVER[‘REMOTE_ADDR’])  and ($userdata[‘user_ip’] !== «0»)))
{
setcookie(«id»«»time() — 3600*24*30*12«/»);
setcookie(«hash»«»time() — 3600*24*30*12«/»);
print 
«Хм, что-то не получилось»;
}
else
{
print 
«Привет, «.$userdata[‘user_login’].«. Всё работает!»;
}
}
else
{
print 
«Включите куки»;
}
?>

Для защиты формы логина от перебора, можно использовать капчу.

Хочу отметить, что здесь я рассматривал авторизацию основоную на cookies, не стоит в комментариях кричать, что сессии лучше/удобнее и т.д. Спасибо.

Примечания:
1. mysql_select_db(«testtable»); // нелогичное название базы, testdb лучше
2. Нужно использовать mysql_real_escape_string()
3. Убирать лишние пробелы нет смысла, так как их не пропустит вот эта строка:
if(!preg_match(«/^[a-zA-Z0-9]+$/»,$_POST[‘login’]))

Восстановление пароля MySQL

Останавливаем сервис:

и перезапускаем его вручную с опцией игнорирования привелегий:

Теперь мы можем задать новый пароль:

И перезапускаем MySQL в штатном режиме:

 

Asterisk – храним CDR в БД MySQL

Должны быть установлены следующие компоненты:

— Mysql Server 5 and Client
— asterisk-1.4.22
— asterisk-addons-1.4.7

#Скачиваем Asterisk-addons с Digium:

 

1
2
3
4
5
6
cd /usr/src
wget <a title="http://downloads.digium.com/pub/asterisk/releases/asterisk-addons-1.4.7.tar.gz" href="http://downloads.digium.com/pub/asterisk/releases/asterisk-addons-1.4.7.tar.gz">http://downloads.digium.com/pub/asterisk/releases/asterisk-addons-1.4.7....</a>
tar xvfz asterisk-addons-1.4.7.tar.gz
cd asterisk-addons-1.4.7/cdr/
vi cdr_addon_mysql.c
add #define MYSQL_LOGUNIQUEID after #define DATE_FORMAT “%Y-%m-%d  %T”

 

1
2
3
cd ..
./configure
make menuselect

Проверяем, загружен ли модуль:

1
2
3
4
5
6
7
8
9
10
11
—> 1. Applications
[*] 1. app_addon_sql_mysql
2. Call Detail Recording
[*] 1. cdr_addon_mysql
3. Channel Drivers
4. Format Interpreters
5. Resource Mod
then q (quit) and S (save)
make && make install

Редактируем файл /etc/asterisk/cdr.conf

1
2
3
4
vi /etc/asterisk/cdr.conf
[general]
enable=yes

Редактируем файл /etc/asterisk/cdr_mysql.conf

1
2
3
4
5
6
7
8
9
[global]
hostname=localhost
dbname=asterisk
table=cdr
password=pass01234
user=asterisk
port=3306
;sock=/tmp/mysql.sock
;userfield=1

Редактируем файл /etc/asterisk/modules.conf

1
vi /etc/asterisk/modules.conf

добавляем следующие строки (если нет):

1
load => cdr_addon_mysql.so

Создаем БД, таблицы и разрешения.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
ipbbx01:~# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 2
Server version: 5.0.32-Debian_7etch5 Debian etch distribution
Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the buffer.
mysql> create database asterisk;
mysql> use asterisk;
mysql> CREATE TABLE cdr (
calldate datetime NOT NULL default ‘0000-00-00 00:00:00′,
clid varchar(80) NOT NULL default ”,
src varchar(80) NOT NULL default ”,
dst varchar(80) NOT NULL default ”,
dcontext varchar(80) NOT NULL default ”,
channel varchar(80) NOT NULL default ”,
dstchannel varchar(80) NOT NULL default ”,
lastapp varchar(80) NOT NULL default ”,
lastdata varchar(80) NOT NULL default ”,
duration int(11) NOT NULL default ‘0′,
billsec int(11) NOT NULL default ‘0′,
disposition varchar(45) NOT NULL default ”,
amaflags int(11) NOT NULL default ‘0′,
accountcode varchar(20) NOT NULL default ”,
userfield varchar(255) NOT NULL default ”,
uniqueid varchar(32) NOT NULL default ”
);
ALTER TABLE cdr ADD INDEX ( calldate );
ALTER TABLE cdr ADD INDEX ( dst );
ALTER TABLE cdr ADD INDEX ( uniqueid );
You can add more indices if you want.
mysql> q
[/mysql]
Не забываем дать разрешения пользователю asterisk@localhost для  работы с БД MySQL:
[mysql]
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> on asterisk.*
-> to 'asterisk'@'localhost';
Query OK, 0 rows affected (0.00 sec)

Проверяем соединение:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ipbx01:~# mysql -h localhost -u asterisk -p asteriskmysql> show tables;
+——————–+
| Tables_in_asterisk |
+——————–+
| cdr |
+——————–+
1 row in set (0.00 sec)
mysql> desc cdr;
+————-+————–+——+—–+———————+——-+
| Field | Type | Null | Key | Default | Extra |
+————-+————–+——+—–+———————+——-+
| calldate | datetime | NO | MUL | 0000-00-00 00:00:00 | |
| clid | varchar(80) | NO | | | |
| src | varchar(80) | NO | | | |
| dst | varchar(80) | NO | MUL | | |
| dcontext | varchar(80) | NO | | | |
| channel | varchar(80) | NO | | | |
| dstchannel | varchar(80) | NO | | | |
| lastapp | varchar(80) | NO | | | |
| lastdata | varchar(80) | NO | | | |
| duration | int(11) | NO | | 0 | |
| billsec | int(11) | NO | | 0 | |
| disposition | varchar(45) | NO | | | |
| amaflags | int(11) | NO | | 0 | |
| accountcode | varchar(20) | NO | | | |
| userfield | varchar(255) | NO | | | |
| uniqueid | varchar(32) | NO | MUL | | |
+————-+————–+——+—–+———————+——-+
16 rows in set (0.00 sec)
mysql>

Данный этап завершен! Теперь проверяем, загружен ли mysql модуль.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ippbx01# asterisk -r
Asterisk 1.4.20, Copyright (C) 1999 - 2008 Digium, Inc. and others.
Created by Mark Spencer
Asterisk comes with ABSOLUTELY NO WARRANTY; type ‘core show  warranty’ for details.
This is free software, with components licensed under the GNU  General Public
License version 2 and other licenses; you are welcome to  redistribute it under
certain conditions. Type ‘core show license’ for details.
=========================================================================
Connected to Asterisk 1.4.20 currently running on asterisk88 (pid =  26648)
Verbosity is at least 3
ippbx01*CLI> stop now
ippbx01*CLI>
Disconnected from Asterisk server
ippbx01# safe_asterisk
ippbx01# asterisk -r
Asterisk 1.4.20, Copyright (C) 1999 - 2008 Digium, Inc. and others.
Created by Mark Spencer
Asterisk comes with ABSOLUTELY NO WARRANTY; type ‘core show  warranty’ for details.
This is free software, with components licensed under the GNU  General Public
License version 2 and other licenses; you are welcome to  redistribute it under
certain conditions. Type ‘core show license’ for details.
=========================================================================
Connected to Asterisk 1.4.20 currently running on asterisk88 (pid =  26880)
Verbosity is at least 3
ippbx01*CLI> cdr mysql status
<h2>Connected to asterisk@localhost, port 3306 using table cdr for 15  seconds.</h2>
Wrote 0 records since last restart.
ippbx01*CLI> quit

Вот и все, хранение CDR в БД MySQl у нас работает.

 

MySQL: cравнение даты (datetime) через оператор BETWEEN

Оператор BETWEEN идеально подходит для сравнения диапазона между датами (datetime). Но тут есть подводные камни. Например, есть задача – выбрать данные из таблицы за некоторый промежуток времени (с ’2008-08-14′ по ’2008-08-23′).

Рекомендации:
1. Выполняя любые сравнения, приводить все данные к одному типу.
2. Если один операнд имеет значение типа TIMESTAMP или DATETIME, а другой является константой, операнды сравниваются как значения типа TIMESTAMP. А это значит, что если была строка в виде ’2008-08-14′, то она автоматически преобразуется в TIMESTAMP ’2008-08-14 00:00:00′ и это влияет на результат запроса.
3. Над данными, которые участвуют в условиях сравнения желательно не делать никаких операций – это позволяет для них использовать индексы, иначе они игнорируются.

Примеры запросов с BETWEEN и без него:

# Поле created_at - тип DATETIME
# КОРРЕКТНЫЕ ЗАПРОСЫ

# 1: Индексы для created_at поля не используются.
# Условие BETWEEN '2008-08-14' AND '2008-08-23'
# преобразуется в BETWEEN '2008-08-14 00:00:00' AND '2008-08-23 00:00:00'.
SELECT * FROM news
WHERE DATE(created_at) BETWEEN '2008-08-14' AND '2008-08-23';

# 2: Оператор BETWEEN не используем, но тоже не самый лучший вариант, индексы не используются
SELECT * FROM news
WHERE DATE(created_at) >= '2008-08-14' AND DATE(created_at) <= '2008-08-23'; # 3: Строки '2008-08-14 00:00:00' и '2008-08-23 23:59:59' не приведены к типу данных DATE SELECT * FROM news WHERE created_at BETWEEN '2008-08-14 00:00:00' AND '2008-08-23 23:59:59'; # 4: Самый лучший вариант, привели к типу DATETIME, индексы будут использоваться SELECT * FROM news WHERE created_at BETWEEN STR_TO_DATE('2008-08-14 00:00:00', '%Y-%m-%d %H:%i:%s') AND STR_TO_DATE('2008-08-23 23:59:59', '%Y-%m-%d %H:%i:%s'); ############################# # НЕПРАВИЛЬНЫЕ ЗАПРОСЫ # 5: Строки '2008-08-14' и '2008-08-23' преобразуются в TIMESTAMP и дополняются '00:00:00' SELECT * FROM news WHERE created_at >= '2008-08-14' AND created_at <= '2008-08-23';

# 6: Аналогично запросу 5
SELECT * FROM news
WHERE created_at BETWEEN STR_TO_DATE('2008-08-14', '%Y-%m-%d') AND STR_TO_DATE('2008-08-23', '%Y-%m-%d');

Получаем самый лучший запрос:

SELECT * FROM news
WHERE created_at BETWEEN STR_TO_DATE('2008-08-14 00:00:00', '%Y-%m-%d %H:%i:%s')
AND STR_TO_DATE('2008-08-23 23:59:59', '%Y-%m-%d %H:%i:%s');

Ссылки по теме:
MySQL 5.1 Reference Manual :: 11.2.3 Comparison Functions and Operators :: Operator BETWEEN
MySQL 5.1 Reference Manual :: 11 Functions and Operators :: 11.6 Date and Time Functions
Search by Date or Timestamp in MySQL