LINUX.ORG.RU

Сообщения JANB

 

[решено] QScrollArea не растягивает виждет внутри себя. А хочется.

Форум — Development

Если я просто засуну внутрь MainWindow слой QVBoxLayout в котором будет 30 кнопок - каждая кнопка растянется по ширине MainWindow и это круто! http://i.imgur.com/W5vxdUR.png

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
	QVBoxLayout *mainLayout = new QVBoxLayout();
	
	for (int i = 0; i < 30; i++) {
		QPushButton *but = new QPushButton();
		but->setText("asdas");
		mainLayout->addWidget(but);
	}

	this->setLayout(mainLayout);
}

Но кнопок очень много, еще могут быть там таблицы и куча других виджетов. Я хочу добавить вертикальный скролл и при этом сохранить растяжение по горизонтали.
На помощь не приходит QScrollArea. То есть приходит, но плохо.

// Наследуюсь от QScrollArea
COutlookContainer::COutlookContainer(QWidget *parent) :
    QScrollArea(parent)
{
	QVBoxLayout *scrollLayout = new QVBoxLayout();
	
	for (int i = 0; i < 30; i++) {
		QPushButton *but = new QPushButton();
		but->setText("asdas");
		scrollLayout->addWidget(but);
	}
	
	QWidget *contianerWidget = new QWidget();  //временный виджет, потому что QScrollArea не принимает QLayout
	contianerWidget->setObjectName("contianerWidgetId");
	contianerWidget->setLayout(scrollLayout);
	
	this->setWidget(contianerWidget);
	this->setAlignment(Qt::AlignCenter);
}


MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
	COutlookContainer *container = new COutlookContainer();
	QHBoxLayout *mainLayout = new QHBoxLayout();
	mainLayout->addWidget(container);
	this->setLayout(mainLayout);
}

Cкролл появляется, но кнопки сжимаются до минимума... http://i.imgur.com/g2JB1tM.png

/* подсветочка */
COutlookContainer {
	background-color: white;
	border: 1px solid black;
}

COutlookContainer  QWidget#contianerWidgetId {
	background-color: green;
	border: 1px solid red;
}

Отчасти помогает contianerWidget->setMinimumWidth(480); но я никогда заранее не знаю ширину.

В общем, мужики, где я неправ?

 

JANB
()

python перенаправление ввода в Popen (doxygen)

Форум — Development

Был баш скрипт который генерировал документацию. Там происходит подмена переменной, поэтому doxygen вызывается с параметром ('-') чтобы читал из stdin.

( ( cat $DOXYFILE ; echo "OUTPUT_DIRECTORY=$RESULT_DOXYGEN_DIR/" ) | doxygen - ) >> $LOGFILE 2>&1

И этот код отлично работал. Встала задача переписать это под питончик. Да еще и направить stdout и stderr в файл


sys.stderr = open("/tmp/tmp_stder.log", "w+")
sys.stdout = open("/tmp/tmp_stdout.log", "w+")

errcode = subprocess.call(['doxygen','-'], stdin=file_doxy, stdout=sys.stdout, stderr=sys.stderr, shell=False)
print errcode

Не выводит ничего никуда. Может быть это баг в библиотеке subprocess?

 , ,

JANB
()

python && unix permissions (gitlab)

Форум — Development

Есть директория /home/git/repositories с правами 770 и uid=git,gid=git

user1@gitserver:~$ ls -la /home/git/ | grep repo
drwxrws--- 42 git  git  4096 Jun 30 17:02 repositories

Есть пользователь www-data, который добавлен в группу git (чтобы смотреть содержимое этой директории)

user1@gitserver:~$ id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data),1001(git)
user1@gitserver:~$ id -G www-data
33 1001
user1@gitserver:~$ id -g www-data
33

От пользователя www-data я запускаяю скипт на питоне который дергает os.listdir('/home/git/repositories') и падает с сообщением OSError: [Errno 13] Permission denied: '/home/git/repositories/'

def functn()
    repo_dir = '/home/git/repositories'
    logg('CURRENT USER: getresuid && getresgid')
    logg(os.getresuid())
    logg(os.getresgid())
    logg('CURRENT USER: getgroups')
    logg(os.getgroups())
    logg(os.listdir(repo_dir))  <-- here is fault

Вывод скрипта

'CURRENT USER: getresuid && getresgid'
(33, 33, 33)
(33, 33, 33)

'CURRENT USER: getgroups'
[33]                            <-- почему-то группа git не отображается =(

Пользователь www-data добавлен в группу git, почему он не может посмотреть содержимое этой директории?!

 ,

JANB
()

gitlab + doxygen != автогенерация документации

Форум — Admin

gitlab + doxygen не дружат

Всем привет.

На работе стоит гитлаб, где есть куча проектов. Большая часть из них содержит подробную документацию внутри кода с использованием doc-блоков. На локальном компьютере документация отлично генерируется через doxygen.

Есть задача централизовано генерировать по всем этим проектам документацию на самом сервере gitlab и иметь доступ к ней. Причем, для оперативности процесса, хочется после каждого «git push» на gitlab-сервер, чтобы документация генерировалась заново.

То есть алгоритм такой: На сервер приходят новые коммиты, обновляется git-репозиторий, запускается doxygen по текущему git-репозиторию, doxygen складывает результат своей деятельности в определенную папку в которую смотрит веб-сервер и отдает оттуда результат.

Сейчас я написал post-recieve hook для git'a. Можно посмотреть тут - http://pastebin.com/MecjMUfs

Работает он так: Если в папке с проектом есть doxygen/Doxyfile.cfg, он генерирует имя проекта исходя из его пути и запускает doxygen.

Громадный недостаток в том, что этот скрипт нужно класть вручную в каждый проект на gitlab. Более того, в свежесозданные проекты его тоже нужно будет класть.

Как Вы решаете задачу генерации документации по своему коду?

Может я неправ и мне не нужно чтобы документация генерировалась автоматически? Может быть достаточно скрипта который будет по крону раз в день ходить по всем папкам gitlab-овских репозиториев и генерировать документацию раз в день?

 ,

JANB
()

Массив из одного элемента вместо указателя.

Форум — Development

В работе с libbson постоянно используется конструкция вида type var_name[1]

например тут - http://api.mongodb.org/c/0.4/bson.html

bson b[1];
bson_init( b );
bson_append_int( b, "count", 1001 );
bson_finish( b );
bson_destroy( b );

что не очень очевидно (на мой вкус). Понятно, что используется имя массива как указатель на первый элемент. Но почему не делается это явно?

Например так:

bson b;
bson_init( &b );
bson_append_int( &b, "count", 1001 );
bson_finish( &b );
bson_destroy( &b );

Ну, или если сильно не хочется писать амперсант, то

bson bs;
bson *b = &bs;
bson_init( b );
bson_append_int( b, "count", 1001 );
bson_finish( b );
bson_destroy( b );

Если ли какие-нибудь преимущества записи указателя как массива из одного элемента, и, вообще, блин, зачем так непонятно писать?

 ,

JANB
()

Двойные скобки вокруг объявления в условии

Форум — Development

Когда в условии делаешь объявление с присваиваением - всё работает, когда вокруг этого объявления ставишь еще одни вторые скобки - компилятор ругается.

#include <stdio.h>

int main(void)
{

	int i = 5;
	
	if (i == 5)  // компилируется норм
		printf("i equal five!\n");
	
	if ((i == 5))   // компилируется норм
		printf("i equal five! with double parentheses\n"); 
	
	if (int j = 5)   // компилируется норм
		printf("j equal five!\n");
	
	if ((int g = 5))   // ошибка компиляции 
		printf("g equal five!\n");


	return 0;
}

Вываливается с ошибкой

janb@janb~: g++ main.cpp 
main.cpp: In function 'int main()':
main.cpp:22:7: error: expected primary-expression before 'int'
  if ((int g = 1))
       ^
main.cpp:22:7: error: expected ')' before 'int'
main.cpp:23:28: error: expected ')' before ';' token
   printf("j equal five!\n");
                            ^

Compilation exited abnormally with code 1 at Mon Jul  6 13:24:18

Поиграться можно тут

http://cpp.sh/3csy

 ,

JANB
()

Перегрузка оператора вывода в поток

Форум — Development

Пишу свой логгер, работающий со всем подряд (позволяющий выводить логи куда угодно) есть желание писать так:

CMyLogger logger;
logger << "message" << 007 << "any message";

Для этого пытаюсь перегрузить оператор вывода в поток:

#include <iostream>

class CClass {
public:
	int i;
	
	CClass() { i = 55;}

	void operator<<(int inttt) {
		std::cout << " [" << inttt << "] " << std::endl;
	}
	
};

int main(int argc, char **argv)
{
	CClass clss;

	clss << 535 << 44;


	return 0;
}

Выдает ошибку

g++ oper.cpp -o oper
oper.cpp: In function 'int main(int, char**)':
oper.cpp:25:17: error: invalid operands of types 'void' and 'int' to binary 'operator<<'
  clss << 535 << 44;

При этом, если написать просто

clss << 535;
, то спокойно компилируется и работает.

 ,

JANB
()

Паттерн стратегия ужасен?

Форум — Development

Привет. Паттерн стратегия ужасен!

Есть абстрактный класс CItem. От него есть производные CItemChild1, CItemChild2 - которые хранят различные наборы данных.

Ниже псевдокод, не ругайтесь

class CItem {
	int my_rtti;
	int commonVal;
};
class CItemChild1 : public CItem {
	int my_rtti = 1;
	int val11;
	int val12;
};
class CItemChild2 : public CItem {
	int my_rtti = 2;
	int val22;
	int val23;
	int val24;
};

Есть задача отображать данные из производного от класса CItem (CItemChild1 или CItemChild2). Отображение зависит от конкретного класса.

Я на главный виджет добавил QStackWidget (показывает одновременно только один виджет) и в него поместил два виджета (widget1 и widget2) для отображения данных.


class QMyWidget : public QWidget {
	virtual void load(CItem *_itm) = 0;
};

class CWidget1 : public QMyWidget {
	virtual void load(CItem *_itm) { ... };
};
class CWidget2 : public QMyWidget {
	virtual void load(CItem *_itm) { ... };
};

class MainWidget {
	CWidget1 *widget1;
	CWidget2 *widget2;
}

// отображение данных полученных откуда-нибудь
void MainWidget::show(CItem *_itm)
{
	if (_itm->my_rtti == 1) {
		QStackWidget->setCurrentWidget(widget1)
		CItemChild1 *chld1 = (CItemChild1 *) _itm;
		widget1.load(chld1);
	}
	else {
		QStackWidget->setCurrentWidget(widget2)
		CItemChild2 *chld1 = (CItemChild2 *) _itm;
		widget2.load(chld2);
	}
}

Но, я прочитал в книжке по паттернам, что использовать if для выбора типа плохо.

И, как следует из паттерна Стратегия, нужно делать совсем иначе...


class CItem {
	int commonVal;
	virtual QWidget *getWidget(void) = 0;
};
class CItemChild1 : public CItem {
	int val11;
	int val12;
	virtual QWidget *getWidget(void) {
		return new (QWidget *) new CWidget1; // можно сделать синглтоном
	}
};
class CItemChild2 : public CItem {
	int val22;
	int val23;
	int val24;
	virtual static QWidget *getWidget(void) {
		return new (QWidget *) new CWidget2; // можно сделать синглтоном
	}
};

void MainWidget::load(CItem *_itm)
{
	if (QStackWidget->currentWidget() != NULL)
		delete QStackWidget->currentWidget();
	widget = _itm->getWidget();
	QStackWidget->setCurrentWidget(widget)
	widget.load(_itm);
}

1. Какие возможные ошибки таит этот способ?

Мне не нравится идея делать создание виджета синглтоном. Но мне и не нравится то, что указатель созданный через getWidget приходится удалять в MainWidget::load.

2. Как видите, способ сделать это через жопу я знаю. А как это сделать «красиво»?

 , , ,

JANB
()

NoSQL, только как MongoDB

Форум — Development

Пишу проект на Qt, возникла необходимость хранить key-value объекты где-нибудь у пользователя без необходимости установки отдельного сервиса.

Раньше бы взял SQLite, но сейчас же бум NoSQL, да и переводить древовидные объекты в таблицы нет желания. Подскажите что сейчас все используют? Производительность сильно не важна, зато важна поддержка C++.

 ,

JANB
()

Нет ошибки сегментации при попытке доступа по неинициализированной памяти.

Форум — Development

Код (краткое описание):

Есть примитивный класс tmp;

Создаю указатель obj на этот класс (без new).

Вывожу на экран отладочную информацию:
адрес_указателя, адрес_экземпляра, значение_члена_экземпляра. 

Создаю экземпляр класса по этому указателю (new) - вызывается конструктор.
Вывожу на экран отладочную информацию.

Присваиваю члену экземпляра значение.
Вывожу на экран отладочную информацию.

Освобождаю память по указателю obj оператором delete - вызывается деструктор.
Вывожу на экран отладочную информацию.

Снова присваиваю члену экземпляра значение.
Вывожу на экран отладочную информацию.

Снова освобождаю память по указателю obj оператором delete - СНОВА вызывается деструктор.
Вывожу на экран отладочную информацию.

Код:
#include "iostream"

class tmp {
public:
	int ii;
	tmp() : ii(123) {std::cout << "__construct" << std::endl;}
	~tmp() { std::cout << "__destruct" << std::endl; }
};
	
int main(int, char **)
{
	tmp *obj;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	obj = new tmp();
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;

	obj->ii = 4;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	delete obj;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	obj->ii = 5;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;

	delete obj;
	std::cout <<&obj <<" " <<obj <<" " <<obj->ii <<std::endl <<std::endl;
	
	return 0;
}

Собираю под оффтопиком без оптимизации так: g++ test_delete.cpp -Wall -O0

Вывод:

a.exe
0x22fecc 0x22ffe0 -1

__construct
0x22fecc 0x3e25e8 123

0x22fecc 0x3e25e8 4

__destruct
0x22fecc 0x3e25e8 0

0x22fecc 0x3e25e8 5

__destruct
0x22fecc 0x3e25e8 4072936

Я считаю, что segfault должен был произойти еще на первой строчкепри попытке вывести адрес объекта - << obj. Ну, или по крайней мере тут: << obj->ii.

Почему не падает?

 , ,

JANB
()

Нужно ли ФП обычным смертным программистам?

Форум — Development

Я c++ джуниор, работаю в интересной компании. Я хочу развиваться как программист.

Что делать с ООП понятно: книжки по паттернам и наизусть свежие стандарты. Но что делать с ФП? Есть ряд вопросов.

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

Перемещено mono из talks

 , ,

JANB
()

Проектирование Qt-приложения. Связь QListWidget и QVector

Форум — Development

У меня есть структура, содержащая информацию об виджете-объекте pObj и указатель на него

 typedef struct {
    QPointF p1;
    QPointF p2;
    QString name;
    QWidget *pObj;
} TMyObj;

Эти структуры складываются в

QVector<TMyObj> myStructArr

Есть необходимость выводить эти структуры (и взаимодействовать с ними) через QListWidget - то есть заполнить его значениями вектора myStructArr и обрабатывать его события, получая связанные с ними элементы вектора.

Когда-то давно (когда я писал на Delphi) я просто заполнял QListWidget элементами QListWidgetItem а при клике получал номер выбранного элемента i = QListWidget::selected() и нужный мне элемент находил в векторе: MyEl = myStructArr[i].

Но, мне кажется что здесь нужно немного ООП.

Например, создать классы:
- MyListWidgetItem наследующийся от QListWidgetItem и содержащий в себе эту структуру.
- MyListWidget наследующийся от QListWidget и добавить метод, возвращающий структуру из MyListWidgetItem

Как вообще это делается в цивилизованном мире?

Под рукой 900-страничная книга где подробно описывается сам Qt, но нет примеров проектирования приложений и решения реальных задач.

 , ,

JANB
()

telelift своими руками

Форум — Talks

Всем привет.

Кто знает как устроена система колесо-рельс в продукции компании telelift? В сети не нашел. Там используются зубчатая передача или просто очень плотное прилегание колес к профилю рельса?

Хочу попробовать сделать такую штуку - нужно чтобы машинка (10кг) могла забираться по рельсам вертикально вверх. И спускаться.

http://fr.telelift-logistic.com/assets/components/phpthumbof/cache/Telelift_Loesung_Detailseite_Bibliothek_L%C3%B6sung_1.586fcdebceac8b4021c0ff17c283abeb165.jpg

 ,

JANB
()

конвертирование координат из 3D в 2D

Форум — Development

В трехмерном пространстве есть плоскость заданная уравнением Ax + By + Cz +D = 0

На ней лежат две точки T1 (x,y,z) и T2 (x,y,z). Середина отрезка образованная этими точками должна стать началом новой двумерной системы координат (0,0), а прямая, проходящая через эти точки - осью ОХ.

Пытаюсь реализовать функцию конвертирования координат любой точки из трехмерного пространства в координаты в новой двумерной системе координат.

Если у кого есть готовые примеры было бы круто. Вручную фигачить направляющие косинусы не айс.

 , ,

JANB
()

Си Среднее арифметическое больших чисел

Форум — Development

Нужно найти среднее арифметическое большого количества относительно больших чисел. Пока задача своится к поиску среднего арифметического 30000 чисел, каждое из которых примерно равно 20000 (+-500). Данные поступают из файла.

Самое простое - писать в массив, потом сумму делить на количество. Сумму хранить, разумеется, в double. Но, так как файл может быть произвольной длины, теоретически могут загрузить и файл раз в 100 больше. Есть желание использовать какой-нибудь более продвинутый алгоритм, пусть даже более затратный с точки зрения процессора. Знаете какой-нибудь такой?

 ,

JANB
()

Большой PHP-класс, работающий с БД

Форум — Web-development

Всем привет! Мне по работе передали один проект на великом и могучем PHP. Обычное веб-приложение. Но очень много работы с БД - много разных выборок и вставок для каждой группы данных. Посколько кода много (сотни функций, автор разбил работу с БД на разные классы по сущностям: пользователи, группы, логи...

Чтобы не «тащить» за собой всегда кучу экземпляров разных классов, он создал один главный класс «dtb» конструктору которого передает ссылку на подключение к базе, а он в свою очередь заполняет свои public поля экземплярами других классов.

Выглядит очень странно:

http://pastebin.com/MGha5CmY

/* Класс поля которого ($user, $log, ...) будут содержать
       экземпляры других классов для работы с БД   
*/
class dtb {
	public $user = null; // экземпляр класса dtbUser
	public $log = null;  // экземпляр класса dtbLog
	// и еще десяток разных
	
	private function __construct(&$connectionLink) {
		if ($connectionLink instanceof MongoDB) {
			$this->user = new dtbUser($connectionLink);
			$this->log = new dtbLog($connectionLink);
			// ...
		}
		else 
			trigger_error('wrong connection', E_USER_ERROR);
	}
}


class dtbItem {
	protected $db = null;
	function __construct(&$connectionLink)
		$this->db = $connectionLink;
}

class dtbUser extends dtbItem{
	public function getOne() {
		$coll = $this->db->selectCollection('users');
		$obj = $coll->findOne();
		return $obj;
	}
	// куча других функций


class dtbLog extends dtbItem{
	public function getTwo() {
		$coll = $this->db->selectCollection('log');
		$obj = $coll->findOne();
		return $obj;
	}
	// куча других функций
}


/* Работает это так: */

$conn = new MongoClient();
$dtbs = new dtb($conn);

var_dump( $dtbs->user->getOne() );
var_dump( $dtbs->log->getTwo() );

Беда этого способа в том, что из класса dtbUser нельзя получить методы класса dtbLog и проектировщик каждый раз описывал всё заново в каждом классе.

А как правильно в PHP реализуется работа с БД когда очень много (сотни) функций получения данных?
И вообще, как правильно в PHP реализуется работа с БД?

p.s. класс dtb инстанцируется как синглтон (но это не важно)

 , ,

JANB
()

Один экземпляр python-daemon

Форум — Development

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

Для демонизации использую python-daemon из PEP-3143. В общем случае, демон выглядит так:

# -*- coding: utf-8 -*-
import os
import daemon
import time

PIDFILE='/tmp/foo.pid'

class App():
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path =  PIDFILE
        self.pidfile_timeout = 5
    def run(self):
        while True:
            print "test..."
            time.sleep(10)

    
app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()

Но, несмотря на pid-файл второй демон запускается спокойно.

Самое простое что пришло в голову - проверять os.path.exists(PIDFILE), а потом try os.kill(pidfile.read_pid(), 0) и ловить except OSError

Но, выглядит как-то костылевато.

Когда гуглил, нашел функцию http://www.thecodingforums.com/threads/single-instance-daemons.644188/

def single_instance(id):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
    sock.bind('\0' + id)
    return sock

Но, ума не приложу как ей пользоваться, она у меня валится на sock.bind

Еще я нашел такую проверку (средствами самого python-daemon):

pidfile = daemon.pidfile.TimeoutPIDLockFile("/tmp/mydaemon.pid", -1)
if daemon.runner.is_pidfile_stale(pidfile):
Но она вообще непонятно как работает - файл /tmp/mydaemon.pid не создается и is_pidfile_stale всегда возвращает false.

Как правильно ограничивать количество копий процесса? Можете просто ткнуть в доки или бросить ссылкой.

 ,

JANB
()

Архитектура демона на питоне и общение с ним

Форум — Development

Вот прямо щас пишу демона для Asterisk на питоне, смотрю в этот гайд http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

Суть работы: Когда демону приходит задание (json-объект) он либо откладывает его, либо начинает выполнять сразу (создание некоторого количества файлов в /tmp, перемещение их в определенную папку и её мониторинг на предмет их изменения/исчезновения). На протяжении всей работы он должен знать какие задания у него сейчас есть, какие он выполнил и что делает сейчас. После экстренного выключения / остановки он должен не терять эти самые задания. В любой момент работы он может получить запрос состояния, на который он должен вернуть json-документ со списком заданий и ходом выполнения.

Демона пишу первый раз, пока не уверен что выбрал правильный путь. Чтобы хранить задания, нужно внешнее хранилище. Я хочу использовать mongodb.

Как правильно организовать хранение списка выполняющихся задач?

Можно вообще всё общение сделать через mongo - новое задание сразу класть в mongo (вообще не использовать внутренние переменные) и начинать его выполнение. После выполнения каждого шага, делать запись в mongo. На любой запрос - брать данные из mongo. Таким образом, при аварийном завершении, я легко восстановлю состояние работы и списки задач.

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

Я правильно понимаю?

и второй вопрос: как общаться с python демоном посредством json? Просто получать его как строку через argv и дальше преобразовывать в объект?

p.s. демон будет вызываться только вебсервером, поэтому интересует системное, а не сетевое взаимодействие

 , ,

JANB
()

Нормальная аутентификация на php+mysql+cookies

Форум — Web-development

Предложили сделать веб-проект который будет торчать наружу. Делаю авторизацию. Какие есть потенциальные уязвимости в таком подходе?

Для каждого пользователя системы в mysql-табличке хранится логин, хэш-пароля(от соли) и сама соль. Также есть пустые поля под CURRENT_IP, CURRENT_USER_AGENT и CURRENT_HASH.

При заходе на страничку login.php пользователь вводит свои логин и пароль;
Логин и пароль обрабатываем preg_match - проверяем, чтобы были только буквы и цифры;
Делаем запрос к базе через adodb (там есть плейсхолдеры);
Если есть такой логин, берем из базы соль, хэшируем соль+пользовательский пароль, проверяем совпадение получившегося хэша с хэшем из базы;
Если всё окей, создаем CURRENT_HASH - любая строка, например md5(time() + "123"), заносим её в базу и кладем в $_COOKIES. Также заносим в базу CURRENT_IP = текущий адрес пользователя и CURRENT_USER_AGENT = md5(от текущего значения user-agent пользователя);


При заходе на любую страницу сайта (где требуется авторизация) подключаем файл auth.php со следующим содержимым:

$my_current_hash = $_COOKIES['CURRENT_HASH']

$sql = "
SELECT `USER_ID`, `CURRENT_HASH`, `CURRENT_USER_AGENT`, INET_NTOA(`CURRENT_IP`) as `CURRENT_IP_NTOA`
FROM `users`
WHERE (`CURRENT_HASH` = %s") AND (`CURRENT_IP_NTOA` = %s)
		AND (`CURRENT_USER_AGENT` = %s);
// fetchRow из adodb
$res = fetchRow($sql, $my_current_hash, $_SERVER['REMOTE_ADDR'],
	md5($_SERVER['HTTP_USER_AGENT']));

if ($res)
	echo "success";
else {
	Header('location: you_suck.php');
	exit();
}

Достаточно ли такого подхода для обеспечения безопасности веб-приложения?

 , , ,

JANB
()

RSS подписка на новые темы