Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Оптимизация кода.

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Описание: Если не сложно, посоветуйте, пожалуйста, как оптимизировать код и, возможно, структуру движка.
kto-to
Отправлено: 02 Мая, 2011 - 00:44:32
Post Id


Новичок


Покинул форум
Сообщений всего: 5
Дата рег-ции: Май 2011  


Помог: 0 раз(а)




Здравствуйте!

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

Общий смысл файла index.php:
1. Определяем, авторизован ли пользователь (получаем права и прочую информацию, которая потом пригодится).
2. Определяем, язык на котором выводим контент (если пользователь авторизован, у него в настройках указан язык).
3. По URI находим контент в БД (получаем тип страницы и прочую информации, которая потом пригодится).
4. Подключаем модуль, соответствующий типу страницы (каталог, галерея, контент, ...).


Если не сложно, посоветуйте, пожалуйста, как оптимизировать код и, возможно, структуру движка.


index.php:
PHP:
скопировать код в буфер обмена
  1.  
  2. <?
  3.  
  4. /******************** VARIABLES ********************/
  5. $db_host = "localhost";
  6. $db_port = "3306";
  7. $db_user = "root";
  8. $db_pass = "";
  9. $db_base = "test";
  10.  
  11. $d_user_data = array("nobody"); // Default user value.
  12. $d_language = "en"; // Default language value.
  13. $d_urn = "main";  // Default URN value.
  14.  
  15. /******************** DB ********************/
  16. $db_link = mysql_connect($db_host.":".$db_port, $db_user, $db_pass) or die(mysql_error());
  17. mysql_select_db($db_base, $db_link) or die(mysql_error());
  18.  
  19. /******************** USER ********************/
  20. $user_data = $d_user_data;
  21. if (isset($_SESSION['user']) and isset($_SESSION['pass'])) {
  22.     $_SESSION['user'] = trim($_SESSION['user']);
  23.     $_SESSION['pass'] = trim($_SESSION['pass']);
  24.     if (strlen($_SESSION['user']) > 0 and strlen($_SESSION['pass']) > 0) {
  25.         $sql = mysql_query("SELECT * FROM `users` WHERE user = `".mysql_escape_string($_SESSION['user'])."' AND pass = '".mysql_escape_string($_SESSION['pass'])."' LIMIT 1") or die(mysql_error());
  26.         if (mysql_num_rows($sql) != 1) {
  27.             $user_data = mysql_fetch_row($sql);
  28.         }
  29.     }
  30. } else if (isset($_POST['user']) and isset($_POST['pass'])) {
  31.     $_POST['user'] = trim($_POST['user']);
  32.     $_POST['pass'] = trim($_POST['pass']);
  33.     if (strlen($_POST['user']) > 0 and strlen($_POST['pass']) > 0) {
  34.         $_SESSION['user'] = $_POST['user'];
  35.         $_SESSION['pass'] = md5($_POST['pass']);
  36.         $sql = ("SELECT * FROM `users` WHERE user = '".mysql_escape_string($_POST['user'])."' AND pass = '".mysql_escape_string(md5($_POST['pass']))."' LIMIT 1") or die(mysql_error());
  37.         if (mysql_num_rows($sql) != 1) {
  38.             $user_data = mysql_fetch_row($sql);
  39.         }
  40.     }
  41. }
  42.  
  43. /******************** LANGUAGE ********************/
  44. $language = $d_language;
  45. if ($user_data != $d_user_data) {
  46.     $language = $user_data[4]; // $user_data[4] = language
  47. } else if (isset($_SESSION['language'])) {
  48.     $_SESSION['language'] = trim($_SESSION['language']);
  49.     if (strlen($_SESSION['language']) == 2) {
  50.         $sql = mysql_query("SELECT * FROM `languages` WHERE language = '".mysql_escape_string($_SESSION['language'])."' LIMIT 1") or die(mysql_error());
  51.         if (mysql_num_rows($sql) != 1) {
  52.             $language = $_SESSION['language'];
  53.         }
  54.     }
  55. }
  56. if (isset($_POST['language'])) {
  57.     $_POST['language'] = trim($_POST['language']);
  58.     if (strlen($_POST['language']) == 2) {
  59.         $sql = mysql_query("SELECT * FROM `languages` WHERE language = '".mysql_escape_string($_POST['language'])."' LIMIT 1") or die(mysql_error());
  60.         if (mysql_num_rows($sql) != 1) {
  61.             $_SESSION['language'] = $language = $_POST['language'];
  62.         }
  63.     }
  64. }
  65.  
  66. /******************** PAGE ********************/
  67. $urn = $d_urn;
  68. if (isset($_GET['urn'])) {
  69.     $_GET['urn'] = trim($_GET['urn']);
  70.     $urn = $_GET['urn'];
  71. }
  72. $sql = mysql_query("SELECT * FROM `pages` WHERE `urn` = '".mysql_escape_string($urn)."' LIMIT 1") or die(mysql_error());
  73. $page_data = mysql_fetch_row($sql);
  74. if (mysql_num_rows($sql) != 1) {
  75.     $urn = $d_urn;
  76.     $sql = mysql_query("SELECT * FROM `pages` WHERE `urn` = '".mysql_escape_string($urn)."' LIMIT 1") or die(mysql_error());
  77.     $page_data = mysql_fetch_row($sql);
  78. }
  79.  
  80. /******************** INCLUDE ********************/
  81. $path = "/home/localhost/subdomain/";
  82. include $path.$page_data[1].".php"; // $page_data[1] = type
  83.  
  84. /******************** DB ********************/
  85. mysql_close($db_link);
  86. ?>
  87.  



Дамп базы:
CODE (SQL):
скопировать код в буфер обмена
  1.  
  2. -- phpMyAdmin SQL Dump
  3. -- version 3.2.3
  4. -- http://www.phpmyadmin.net
  5. --
  6. -- Host: localhost
  7. -- Generation Time: May 02, 2011 at 01:36 AM
  8. -- Server version: 5.1.40
  9. -- PHP Version: 5.3.3
  10.  
  11. SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
  12.  
  13. --
  14. -- Database: `test`
  15. --
  16.  
  17. -- --------------------------------------------------------
  18.  
  19. --
  20. -- Table structure for table `pages`
  21. --
  22.  
  23. CREATE TABLE IF NOT EXISTS `pages` (
  24.   `id` int(11) NOT NULL,
  25.   `type` text COLLATE utf8_unicode_ci NOT NULL,
  26.   `urn` text COLLATE utf8_unicode_ci NOT NULL,
  27.   KEY `id` (`id`)
  28. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  29.  
  30. --
  31. -- Dumping data for table `pages`
  32. --
  33.  
  34. INSERT INTO `pages` (`id`, `type`, `urn`) VALUES
  35. (0, 'catalog', 'main'),
  36. (1, 'page', 'page1');
  37.  
  38. -- --------------------------------------------------------
  39.  
  40. --
  41. -- Table structure for table `users`
  42. --
  43.  
  44. CREATE TABLE IF NOT EXISTS `users` (
  45.   `id` int(11) NOT NULL,
  46.   `user` text COLLATE utf8_unicode_ci NOT NULL,
  47.   `pass` text COLLATE utf8_unicode_ci NOT NULL,
  48.   `language` text COLLATE utf8_unicode_ci NOT NULL,
  49.   KEY `id` (`id`)
  50. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  51.  
  52. --
  53. -- Dumping data for table `users`
  54. --
  55.  
  56. INSERT INTO `users` (`id`, `user`, `pass`, `language`) VALUES
  57. (0, 'nobody', '', 'ru'),
  58. (1, 'alfred', 'dd88f82e4a92f5b61f65c456d544d010', 'en'),
  59. (3, 'vasya', 'a2e2fb92e9ea48f1b26b67983ea729a3', 'ru');
  60.  


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

P.S.: Что-то мне подсказывает, что получилось ужасно криво...
 
 Top
Haron
Отправлено: 02 Мая, 2011 - 07:38:17
Post Id



Частый гость


Покинул форум
Сообщений всего: 197
Дата рег-ции: Июнь 2010  
Откуда: Оттуда


Помог: 5 раз(а)




Безопасность:
- Нет контроля того, что приходит от пользователя (GET POST). Поэтому взламывается элементарно. Курите статью про MySQL Injection в википедии. mysql_escape_string - не панацея.
- md5 - легко дешифруется. Есть такая (очень) весёлая программа GPU md5 crack

Структура
- Почитайте про буферизацию вывода. Сильная вещь.
- Не храните короткие строки в полях типа TEXT. Ужасно ресурсоёмкое, и не поддерживающее индексы решение. Храните в VARCHAR.
- Используйте индексы в таблицах. Например повесьте уникальный индекс на поле `urn`.

На этом всё, ниже - чисто рекомендации (Их не обязательно использовать, это моё ИМХО).
- Используйте библиотеки абстракций от БД (Например DBsimple, - сильно экономит время).
- А лучше напишите свою, и желательно под расширение MySQLi.

Смысл в том, чтобы некая абстрагирующая функция (ну например обзовём её query()) - выполняла и
mysql_query, и mysql_fetch_row к примеру, и возвращала уже готовый результат. Принимать она должна строку запроса SQL и параметры.
В неё же (функцию) можно фильтрацию и контроль входящих данных впихнуть.

(Отредактировано автором: 02 Мая, 2011 - 07:39:17)



-----
И чё?
 
 Top
DlTA
Отправлено: 02 Мая, 2011 - 07:42:34
Post Id



Постоянный участник


Покинул форум
Сообщений всего: 2952
Дата рег-ции: Окт. 2010  


Помог: 53 раз(а)




могу посоветовать вынести подключение к базе 7-19 строчка, отдельным файлом, сократит напряги при переносе и дальнейшей разработке.

еще меня всегда смущало, нафига это делать "$_SESSION['pass'] = trim($_SESSION['pass']);"
если мне нравится в пароли пробелы набивать?!

а с этим: $path = "/home/localhost/subdomain/";
тоже буде куча головняка, можно как то так: include("{$_SERVER['DOCUMENT_ROOT']}/...");
 
 Top
Champion Супермодератор
Отправлено: 02 Мая, 2011 - 09:04:41
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




kto-to пишет:
/******************** VARIABLES ********************/
Не надо так делать. Это мусорный комментарий. Если хотетите выделить смысловой блок - оформите его в функцию или (всякие конфиги) вынесите в отдельный файл.

Haron,DlTA - всё по делу, но
Haron пишет:
md5 - легко дешифруется.
Немного не так. md5 вообще не дешифруется. Никак. Атака с использованием радужной таблицы - это не дешифрация, а по сути просто очень эффективная модификация брута. И сломать позволяет далеко не всё. А использование соли делает эти таблицы вообще неэффективными.
kto-to хешировать лучше не пароль, а md5(чудо-строка), где чудо-строка получается путем конкатенации пароля со случайным образом сгенерированной еще одной строкой - солью.
Haron пишет:
Почитайте про буферизацию вывода. Сильная вещь.
Обычная вещь. Да и к чему она тут?
Haron пишет:
Храните в VARCHAR.
а поля type и language можно даже в enum.
 
 Top
Haron
Отправлено: 02 Мая, 2011 - 10:55:35
Post Id



Частый гость


Покинул форум
Сообщений всего: 197
Дата рег-ции: Июнь 2010  
Откуда: Оттуда


Помог: 5 раз(а)




Champion пишет:
Немного не так. md5 вообще не дешифруется. Никак.

Я бы не был столь категоричен: http://eprint[dot]iacr[dot]org/2004/199[dot]pdf
Брутфорс же md5 - сегодня делается в обозримые сроки (Используется CUDA). Неважно, есть соль, или её нетЪ.

Champion пишет:
Обычная вещь. Да и к чему она тут?

К тому, что с буферизацией страница будет отдаваться уже готовой - сразу и вся, а не рисоваться постепенно (порой это очень некрасиво смотрится). А если ещё и закешировать (например в файлы) - +100500 к быстродействию.


-----
И чё?
 
 Top
Champion Супермодератор
Отправлено: 02 Мая, 2011 - 11:10:57
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Я тут вообще не увидел ничего похожего на вывод, поэтому не понял, зачем здесь заводить речь о буферизации)
Я вот могу с таким же успехом посоветовать совершать пробежки в парке - это тоже полезная вещь)
Haron пишет:
http://eprint[dot]iacr[dot]org/2004/199[dot]pdf
Брутфорс же md5 - сегодня делается в обозримые сроки (Используется CUDA). Неважно, есть соль, или её нетЪ.
Ну это не дешифрация. Понятное дело, что любое хэш значение имеет бесконечное число коллизий. Одно дело подобрать одну из коллизий, другое - реальное захешированное значение. Хотя часто можно воспользоваться одним вместо другого.
По поводу CUDA - я думаю, не каждый злоумышленник может ей воспользоваться, тем более для атаки на творчетсво kto-to. Ничего плохого не хочу сказать про kto-to, но думаю, что его сайт не предстваляет интереса для злобных хакеров - только для энтузиастов. Так что соли вполне достаточно.
Кстати, я увидел камень, брошенный в md5, но не увидел ничего предложенного взамен.
 
 Top
Мелкий Супермодератор
Отправлено: 02 Мая, 2011 - 11:21:19
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




Haron пишет:
Брутфорс же md5 - сегодня делается в обозримые сроки (Используется CUDA). Неважно, есть соль, или её нетЪ.

Угу, ещё одна жертва маркетинга, как и я в своё время. Вот вам задание:
KeyCAPTCHA пишет:
скажите пароль для "подписи" вот этих двух строк:

строка1: http:/www[dot]yandex[dot]ru/webmaster|GGGDDDBB[dot][dot][dot]890223344|PRIVET
хэш1: 68B467EE6625898B2B0BF7CFC7B8E6C7

строка2: http:/www[dot]yandex[dot]ru/top|GGGDDDBBB7890223344|100BAKSOV
хэш2: FD9BBA0F534859764BC16BFBD0F493F1

пароль прибавляется к началу строк то есть хэш = MD5( пароль + строка ). Пароль ОДИНАКОВЫЙ для обоих строк.

мой пароль содержит от 20 до 30 символов и имеет только анлгийские большие и маленькие буквы (вобщем длинной около 150 бит) ну это чтобы вам было проще


-----
PostgreSQL DBA
 
 Top
kto-to
Отправлено: 02 Мая, 2011 - 19:06:12
Post Id


Новичок


Покинул форум
Сообщений всего: 5
Дата рег-ции: Май 2011  


Помог: 0 раз(а)




Haron, DlTA, Champion, Мелкий, благодарю за ответы!

1. А что mysql_escape_string() пропустит? По идее, БД должна уметь обрабатывать любые данные, просто их надо предоставить в нужном виде, или я чего-то не так понимаю? Как там SQL-inj провести?
2. Слышал, что md5 лучше использовать с солью. Переделаю. А, на самом деле, какая реальная альтернатива md5?
3. Для буферизации, пока, рано. Тут вывода еще нет. Но обязательно учту, когда буду писать вывод.
4. Да, со структурой БД у меня беда. Переделаю.
5. Подключение к БД сознательно не стал выносить в отдельный файл, потому, что include() замедлит скорость работы скрипта.
6. Оправдано ли использование trim()... Думаю, что стоит оставить, потому, что пробелы по краям редко ставятся сознательно. Хотя... Лишняя функция - лишнее время.
7. $_SERVER['DOCUMENT_ROOT'] - это да. Переделаю.
8. По поводу комментариев уже сломал себе голову... Выносить блоки в функции - увеличить время выполнения сценария, а совсем без комментариев код слабо читабельный.
9. Хотелось бы, чтоб обошлось без этого, но хакерские атаки (не знаю, на сколько профессиональные, но заказные) скорее всего будут.

Да, по поводу библиотеки абстракций от БД... Опять же, она облегчает процесс написания, но замедляет выполнение сценариев. Да и приложения сторонних разработчиков, без крайней необходимости, я использовать не хочу.
 
 Top
Мелкий Супермодератор
Отправлено: 02 Мая, 2011 - 19:32:02
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




1. тоже любопытно. Для базы данных mysql_escape_string вполне достаточно.
2. sha1 есть ещё.
5 & 6 & 8. Это называется "преждевременная оптимизация". Забейте на наносекунды, для них всё равно PHP не подходит и делайте так, чтобы это было удобно.


-----
PostgreSQL DBA
 
 Top
kto-to
Отправлено: 02 Мая, 2011 - 20:16:38
Post Id


Новичок


Покинул форум
Сообщений всего: 5
Дата рег-ции: Май 2011  


Помог: 0 раз(а)




2 Мелкий

О sha1 прочитал. Я так понимаю, что принцип, по сути, такой же, как и у md5. Существенной разницы между ними, я найти не могу. Единственное, возможно использовать их совместно. Или я ошибаюсь?

Преждевременная оптимизация, возможно. Но нет ничего более постоянного, чем что-либо временное. Не хочется в итоге получить две килотонны медленного кода, который надо везде подправить. Возможно php не самый быстрый язык, но именно он мне в данной ситуации позволит относительно быстро добиться цели. И именно от него я сейчас намерен получить максимальную скорость.
 
 Top
Haron
Отправлено: 02 Мая, 2011 - 21:06:48
Post Id



Частый гость


Покинул форум
Сообщений всего: 197
Дата рег-ции: Июнь 2010  
Откуда: Оттуда


Помог: 5 раз(а)




kto-to пишет:
Единственное, возможно использовать их совместно. Или я ошибаюсь?

Совместно - да, хорошая идея

kto-to пишет:
Преждевременная оптимизация, возможно. Но нет ничего более постоянного, чем что-либо временное.

И по поводу абстракций...
Пример - три функции делающих что либо (На входе $var - на выходе $c)

$a = func1($var);
$b = func2($a);
$c = func3($b);

Как думаете, что быстрее и читабельней?
Использование подобных повторяющихся конструкций в коде 100500 раз?
Или единственная конструкция вынесенная в функцию? (Необязательно в отдельный файл)?


-----
И чё?
 
 Top
Champion Супермодератор
Отправлено: 02 Мая, 2011 - 21:13:24
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Haron пишет:
Совместно - да, хорошая идея
Плохая идея. Похоже на панику. Шифровать всем чем можно. md5 + соль и всё будет здорово.
kto-to пишет:
По поводу комментариев уже сломал себе голову... Выносить блоки в функции - увеличить время выполнения сценария, а совсем без комментариев код слабо читабельный.
Правильно сказали - это преждевременная оптимизация. Такой код гораздо сложнее сопровождать, в нем проще ошибиться - и все ради выйгрыша времени, который толком и засечь-то не удастся.
 
 Top
OrmaJever
Отправлено: 02 Мая, 2011 - 21:20:57
Post Id



Активный участник


Покинул форум
Сообщений всего: 7540
Дата рег-ции: Янв. 2010  
Откуда: Чернигов


Помог: 299 раз(а)




Нащёт шифровки, чистая md5 очень устаревает т.к. уже много сервисов по подборке, с сольюя думаю тоже могут распаковать. Я раньше выдрал функцию из phpbb3, она похожа на md5 но мало известна
PHP:
скопировать код в буфер обмена
  1. function _hash_encode64($input, $count)
  2. {
  3.         $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  4.               $output = '';
  5.         $i = 0;
  6.  
  7.         do
  8.         {
  9.                 $value = ord($input[$i++]);
  10.                 $output .= $itoa64[$value & 0x3f];
  11.  
  12.                 if ($i < $count)
  13.                 {
  14.                         $value |= ord($input[$i]) << 8;
  15.                 }
  16.  
  17.                 $output .= $itoa64[($value >> 6) & 0x3f];
  18.  
  19.                 if ($i++ >= $count)
  20.                 {
  21.                         break;
  22.                 }
  23.  
  24.                 if ($i < $count)
  25.                 {
  26.                         $value |= ord($input[$i]) << 16;
  27.                 }
  28.  
  29.                 $output .= $itoa64[($value >> 12) & 0x3f];
  30.  
  31.                 if ($i++ >= $count)
  32.                 {
  33.                         break;
  34.                 }
  35.  
  36.                 $output .= $itoa64[($value >> 18) & 0x3f];
  37.         }
  38.         while ($i < $count);
  39.  
  40.         return $output;
  41. }

(Отредактировано автором: 02 Мая, 2011 - 21:21:12)



-----
Если вы хотя бы 3-4 раза не решите всё выкинуть и начать заново - вы явно что-то делаете не так.
 
 Top
EuGen Администратор
Отправлено: 02 Мая, 2011 - 21:23:07
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Для БД используйте готовые адаптеры (чтобы не писать свои). Zend к примеру.
Остальное можно вынести в модели - создав соответствующие классы.
Объектный подход почти всегда сопутствует масштибаруемости и гибкости - конечно, если применен верно.
Почитайте также про паттерны проектирования.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Мелкий Супермодератор
Отправлено: 02 Мая, 2011 - 21:58:17
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




kto-to пишет:
Не хочется в итоге получить две килотонны медленного кода, который надо везде подправить.

Именно к этому вы и идёте. В зависимости от личных способностей, килобайтах на 20++ кода начнёте нещадно путаться, потеряете контроль над кодом и придёте к решению, что всё это надо выбросить и писать нормально - так, чтобы было удобно разработчику, ведь его время куда дороже машинного.


-----
PostgreSQL DBA
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Наработки по собственным проектам »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB