Май 2009

Смена базы данных на php-проектах

27.05.2009

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

Суть ситуации в том, что люди намеряно сводят работу с базой данных до уровня insert, update, select, delete, создавая особо извращенные варианты доступа к этим самим данным. Любые - лишь бы не SQL. В итоге, понятное дело, без извращений в таких вещах очень сложно сделать простые с точки зрения запросов вещи. Ну например, счетчик посещений сайта и например ORM.

Алгоритм какой будет?

1. Выбрали данные;

2. Увеличили на 1;

3. Сохранили данные.

А что если на сайт почти одновременно зайдут 2 пользователя? :) Причем до шагов этого алгоритма они дойдут параллельно и в одно время. Т.е. 1-й делает выбор данных, потом второй, потом первый - увеличивает счетчик и т.п.? понимаете? :)

В самой базе все проще - UPDATE четотам SET `count`=`count`+1 WHERE четотам. И никаких глюков - потому что запросы будут выполняться последовательно.

Когда же копаешь глубже о причинах таких диких абстракций - оказывается, что все для того, чтобы:

Если заказчик захочет сменить базу данных скажем с MySQL на Oracle - то мы всего лишь переписали бы конфиг и все запалило на ура вместо того, чтобы переколбашивать весь сайт.

Я однажды не выдержал и поспрашивал всех кого знал, а сталкивался ли кто-нить из них с такой задачей - и оказалось что такое всплыло 1 раз на примерно 500-700 проектов, в которых участвовали опрошенные :)

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

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

Выпадают волосы? Срочно лечить - лечение волос москва.

Многострочные строки в javascript

27.05.2009

Мож кто и в курсе, но я не знал и не сразу вкурил. Оказывается,  в джаваскрипте многострочные строки можно писать не только вот так:
var val = 'Индикатор ядовито'+
' гидролизует сернистый газ,'+
' таким образом за синтез';

А еще и вот так:
var val = 'Индикатор ядовито\
гидролизует сернистый газ,\
таким образом за синтез';

Не сказать, чтобы было гораздо читабельнее, но есть и такой вариант :)

Сравнение строк и чисел в MySQL

14.05.2009

За время работы я как-то привык, что если в интовые поля вставлять числа, оформленные как строки - то оно палит. Аналогично и если выбирает по id='5' например то тоже все ок и конвертируется в нужное...

Но вот недавно столкнулся с интересной ситуацией - поле varchar - там лежат числа. И получается что-то вроде:

select '33' > '5';

причем выбирает есесна 0 :) т.е. фолс, т.к. сравнивает строки. Такое вполне очевидно, но привыкаешь постепенно что с нестрогой нет проблем :) вот тебе и такое :)

Антиюзабилити в регистрации и авторизации

14.05.2009

Хотел вначале по посту о каждой - но понял что лучше все написать вместе. Вот самые распространенные тупые решения при создании авторизации пользователей на сайте:

  1. Email в качестве логина -  пожалуй, первое место в списке тупых идей. Сама идея такого подхода как раз-таки направлена на то, чтобы пользователю было проще регистрироваться. Типа вбивать меньше данных и все такое. Но на деле получается как раз наоборот - пользователь регистрируется не только на этом сайте, причем в большинстве случаев он вводит логин и пароль и ни разу не мыло в качестве логина. Он привыкает к этой паре логин-пароль и для него вбивать емэйл просто неочевидно, непривычно, не говоря уже о том, что если мыльников штук 5 - то какой именно был вбит при регистрации - вопрос достойный Что? Где? Когда?. Ну а если в форме авторизации еще и не подписано что вводить надо емэйл - ууууууууу :)
  2. Ограничения на выбор пароля - секъюрность - это круто, несомненно. Только вот пользователь привыкает к своей привычной паре логин-пароль. А вот если привычный пароль не проходит ограничения, выбирает новый, который с 90%-й вероятностью забудет тут же как вбил. На следующем заходе запросит восстановление - и пароль будет пылиться на мыле и каждый раз он будет заходить на мыло, смотреть пароль и вставлять в форму :) Вы считаете, что ваш аккаунт на вашем сайте - самое важно в жизни пользователя? ну-ну :)) Безопасность - это важно, когда нужно. Пусть пользователи сами решают, важен для них ваш сайт или он достоин пароля 12345.
  3. Капча + подтверждение email-а в регистрации - одной капчи с головой хватит чтобы вырубить ботов. Да есть метод леммингов для ее обхода, но много ли кому не влом его прикручивать? С подтверждением по emailу (активацией аккаунта) есть вечная проблема - обязательно у какого-нить письма не будут приходить. Или они в спам уйдут или еще какая-то фигня случится - неважно, так есть и будет. Не лучше ли высылать письмо со ссылкой на отписку, если ввели не правильный мыльник, чем на активацию? Да и настолько ли важно знать мыло пользователя для вашего сайта?
  4. Нераспознаваемая капча - кто-то криворукий создал новый тип капчи и все начали его пользовать. Не знаю видел ли кто - но я, человек из плоти и крови, вбиваю ее верно раза с 10-го.
  5. Капча без возможности перезагрузки - какой бы капча не была простой - обязательно однажды она сгенерит что-то ну просто совсем нечитаемое. А если пользователь уже вбил всю анкету - перегружать страницу не есть круто, ибо чревато потерей данных в некоторых браузерах.
  6. Лишние обязательные поля - какое вам дело как меня зовут или где я живу? Хочу введу хочу нет и нефиг делать это обязательным, поэтому для вас зовут меня "вапва" и фамилия "водаплвопвпвпавап".
  7. Малое ограничение на количество безпроблемных попыток ввода верного пароля - например, после 5 паролей начинает вылетать опять же капча или пишет типа подождите 20 минут. Лично у меня паролей штук 20, не меньше, и юзал я разные в зависимости от ситуации, вначале одни, потом другие и т.п. за лет 10 накопилось немало вариантов... А тут 5 - и потом мучайся... а в сочетании с п.4 - уххх  как весело авторизоваться становится...
  8. Блок при N неверных попыток авторизации - тут скорее дело не в идее блокировать доступ к аккаунту на время если кажется, что подбирают пароль, а в кривой реализации этого некоторыми товарищами. Так как куки чистятся - надо учитывать ip, с которого пытались это сделать, иначе кто угодно набьет другому N попыток авторизоваться всяким шлаком и заблочит ему на время аккаунт.

С чего начать?

02.05.2009

В мире программирования задача никогда не бывает одна, если это так - значит поставлена она не верно. Зачада "Сделать сайт" - поставлена неверно, к примеру. Большие задачи обычно дробятся и каждому периоду работы обычно предшествует список определенных задач на реализацию. Среди таких задач бывают большие - например "Сделать фотогалерею" и тз, дизайн и т.п. по ней. А бывают маленькие - например, сменить фразу "Выбранные товары" на фразу "Корзина".

С чего начать? С больших или с маленьких задач?

Обычно начинают всегда с больших. И так в целом абсолютно здраво делать, когда проектируется новый сайт или вы знаете систему отлично. На маленькие задачи надо меньше сил, а если вначале сделать мелочь - то на большое не всегда останется рвения. Да и если система создается новая - то вначале надо сделать "скелет", а уже потом навешивать мышцы и кожу :)

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

Например, пришел проект написанный фиг знает на чем, фиг знает кем и когда. Что внутри - непонятно. Делаем мелкий таск - изменение надписи. Дело пятиминутное - тупо прогнать поиск по коду (и базе если по коду не найдется) по этому слову - и поменять его. Задачу сделали - и уже кое-чему научились, например, как устроена система локализации, есть ли она вообще. Какие шаблоны есть в коде. Т.е. решение мелкой задачи помогло попутно разобраться с проектом и узнать что-то о нем, без того чтобы специально колупать его и смотреть что там и где. И так далее - от мелкого к крупному.

Такой подход позволяет убить сразу 2-х зайцев:

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

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

$i++ vs. ++$i

02.05.2009

Есть у меня товарищ, который кодит на c++. И как-то в его коде в цикле я заметил, что он пишет не i++; а ++i; - оказалось что так производительнее (ну они сишники вообще помешаны на этом всем). Почему лушче писать так, я как-то поленился разобраться, но пример я естесственно запомнил - и старался по мере сил писать такое же и в php, хуже ведь не будет все равно. Оказалось недавно, что и у нас это тоже оправдано.

Оказывается:

При использовании инструкции $count++ увеличение переменной $count выполняется после того, как будет рассчитано выражение с использованием данной переменной. Например, $i =$count++; — переменной $i будет присвоено значение переменной $count до того, как последнее будет увеличено на единицу. Это означает, что машина должна сохранить значение $count, чтобы использовать его в любом выражении с переменной $count. В инструкции же ++$count значение переменной увеличивается на единицу до вычислений, поэтому нет необходимости хранить временное значение (а это менее накладно). Если инструкция $count++ применяется в выражении, где значение переменной не используется (это называется пустым контекстом), то ее можно безопасно преобразовать в преинкрементную инструкцию.

Конечно, фигня там получается, а не оптимизация, но зато в таком коде сразу видна рука мастера :)

Метод леммингов

02.05.2009

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

На деле же, нормальные ботописцы забили давно болт на распознавание компом капчи - потому что это слишком бессмысленно когда есть Его Величество "Метод Леммингов".

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

Гораздо эффективнее защищаться тем, что может браузер, но не может бот. Например, с выполнением javascript-а насколько я знаю у всех языков реальные проблемы. Конечно, можно пользоваться и браузерами как помошниками в спаме и т.п. - в винде например IE как ком-объект отлично вызывается. Да вот только программист, который это наколбасит будет стоить гораздо больше, чем годы работы голодающих детей банановых стран.

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

Вычисление констант в коде

02.05.2009

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

$seconds_count = 86400;

Не, я тут не буду писать про переменные и т.п. я буду писать про числа. Возьмем число в примере - слету и не разберешь че это такое вообще... Вот если бы:

$seconds_count = 24*60*60;

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

Другими словами, если код транслируется один раз, а потом берется уже откешированый, то смысла в этом нет вообще - ну один раз сделает комп вычисление умножения, которое само по себе очень легкое - что с того? Ну а если же нет - и php-код будет каждый раз интерпретироваться без сохранения промежуточных вариантов - то не проще ли врубить eAccelerator? Да и нужна ли такая типа оптимизация в проекте в котором все положили на реальное ускорение через кеширование?

Объявление объекта без скобок

01.05.2009

Иногда встречаю вот такую вот запись создания нового объекта:

$obj = new Typed;

Вначале мне казалось, что это просто от криворукости программистов и работает также как и массивы, в которых индексы пишутся без кавычек типа $a[index], где автоматом заводится константа с тем же значением и это на удивление работает. Оказалось констант никаких не заводится - а это просто особенность языка.

Оказалось, что такая манера создания классов была описана в мануале по классам и объектом самими разрабочиками php для php4 на php.net.

Вопрос, нафига? В самых распространенных языках программирования везде пишутся скобки после имени класса. IDE от тех же Зендов тоже подсказывает $obj = new Typed(); По-моему, это только запутывает.

P.S. Кстати и в 5-м php та же фигня в описании...

Отправка писем с ошибками администратору

01.05.2009

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

Представим себе проект, который посещает человек 300 в день и у которого внезапно отвалилась база данных. Ну например, место кончилось или еще че-нить. Пользователь, который видит, что страница не загрузилась есстественно попробует ее перезагрузить несколько раз :) для верности. Ну и каждый раз есстественно письмо админу :)

Таким образом, пока админ успеет среагировать - его ящик будет переполнен ну или же, что скорее всего, сайт улетит в бан за спам и потребуется много времени чтобы объяснить почтовикам что он не спамер, а просто так получилось. Я имею ввиду, что спам-фильтр будет резать письма с этого сайта, которые идут на мыло админа.

Чтобы дать этой идее хоть какую-нить жизнь, нужно написать специальный анализатор, который будет разбирать ошибки и недопускать повторного отправления одного и того же, что в принципе довольно геморно, потому что написан он будет на php, стало быть если отвалятся некоторые php-шные части (например, отправка писем :)), то он все равно не сможет выполнять свою задачу.
Так что отправка писем с ошибками администратору - тупая идея

Форматирование sql-кода

01.05.2009

$res = mysql_query("select articles.title, articles.text, articles.id, articles.user_id, users.name from articles left join users on articles.user_id=users.id where $condition order by id desc limit 5, 10");

Такой жестяк часто встретишь, когда пишут код студенты или просто люди торопятся да так что ппц. Нифига не понятно. Запрос написан в стиле write-only. В противовес индусам - нормальные программисты используют определенные правила форматирования кода в запросах. И хоть каждый использует свои, как правило они очень похожи.

(далее…)

Чем echo отличается от print

01.05.2009

На собеседованиях любят задавать самые каверзные вопросы с подколками. Одним из таких вопросов является вопрос о разнице между echo и print. Многие даже очень опытные программисты считают их синонимами, потому что ведут себя они одинаково:

<?php
print "Hello World!";
echo "Hello World!";

И то и то выдаст "Hello World!", однако разница между ними все же есть, просто сложно придумать ситуацию, в которой она была бы заметна:

  1. print возвращает true/false в зависимости от того, удачен вывод или нет. Я не представляю себе ситуации, в которой она бы вернула false, но наверное есть... echo ничего не возвращает;
  2. echo нельзя использовать со скобками, т.е. echo(123) - выдаст ошибку, print(123) - нормально отработает;
  3. Понятное дело что из-за п.1 echo работает быстрее чем print. Разница несущественная, но есть и это неплохо знать;
  4. В echo можно передать несколько параметров для вывода через запятую (echo 123, 'aaaa', 33 ;) и они выведутся последовательно. В print нет.

Я не уверен, все ли я описал тут, но думаю достаточно чтобы выяснить что они ни разу не синонимы. Если кто знает еще - пишите в коменты - буду рад узнать что-нить новое.

Строки и is_int

01.05.2009

Интересное наблюдение вычитал в книжке "Профессиональное программирование в php". Автор пишет, что:

Использование вместо функции is_int регулярного выражения для определения того, является ли $п целым числом, может показаться странным. Однако функция is_int не делает того, что в данном случае требуется. Она только проверяет, типизирована ли переменная $п как строковая или как целочисленная, но не проверяет, является ли значение переменной $п целым числом. Данный нюанс может ввести разработчика в заблуждение, если он использует функцию is_int для проверки данных HTML-форм (среди прочего).

Я как-то не сталкивался с этим раньше и решил проверить. Оказалось действительно:

<?php
var_dump(is_int("56"));
var_dump(is_int(56));

Выдает: bool(false) bool(true) 

Как вставить javascript в smarty

01.05.2009

Недавно постучался ко мне в аську знакомый сеошник с проблемой - дескать не могут они с верстальщиком в уже готовый проект, написанный фиг_знает_кем_кого_уже_нет_рядом, код то ли счетчика то ли еще чего, другими словами javascript вставить не получается. Какой там шаблонизатор, да и вообще на чем проект этот написан, они понятное дело не в курсе, потому что один верстальщик, а второй сеошник а спросить не у кого. Я попросил прислать пример кода в html-ке (текста шаблона) и, как я и ожидал, оказалось что это Smarty.

Если кто не знает, в смарти используются разделители для того, чтобы обозначить что данный кусок кода все-таки написан на смарти а не просто текст. И хоть в доке по нему явно написано, что разделители дескать можно настроить любые какие только душе угодно - на деле же все используют именно то что там по умолчанию ( фигурные скобки ), ибо все готовое написано именно так, а переписывать готовое ради разделителя не айс ни разу.  Вот и получается что код javascript-а, обрамленный в блок (например function foo() { ... }, да или просто любой блок) шаблонизатор воспринимает как директиву Smarty и пытается его исполнить. И чтобы такого не возникало, придумали специальный костыль - обрамлять куски html, в которых встречаются разделители тегами {literal}тут код{/literal}.

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

Грабли с короткими тегами и заголовком xml

01.05.2009

За все время программирования я так привык к тому, что в проекте используется какой-либо шаблонизатор для html-страниц да и вообще все что отдается пользователю идет через какой-то компонент и отвык от проектов с мелкими кусками php-кода прям посреди html-разметки, что просто не мог наступить на эти грабли. Оказывается, если short_open_tag включен (php.ini ну или php_value в .htaccess и т.п.), то  можно поймать вот такую вот проблему:

Если у нас есть php-ка, которая начинается с xml заголовка, то при включенном short_open_tag - заголовок будет интерпретироваться как php-код. Ну собственно вот для наглядности:

info.php c кодом:

<?xml version="1.0" ?>

[Дальше xml или html]

Выдаст: Parse error: syntax error, unexpected T_STRING in ...info.php on line 1

На относительно больших проектах, написаннх ровноруко, такой баг врятли поймаешь, но если писать скажем самопальную rss-ку без mod_rewrite или скажем XML Sitemap, то вполне.

Насчет же тегов мне всегда казалось, что в тех же шаблонах, сделанных например в стиле Zend_View, гораздо удобнее писать <?=$variable?>, чем <?php echo $variable; ?>, но на мелких доделках и самопальных решениях не все может прокатить, поэтому надо быть осторожными и стараться использовать чужие наработки.

Жесткая табуляция vs. Мягкая табуляция

01.05.2009

Чтобы немного прояснить для тех кто не в курсе, напишу определения обоих вещей. Итак:

Жесткая табуляция (hard tabs)— это обычные символы табуляции.

Мягкая табуляция (soft tabs) в действительности вообще не является табуляцией; каждый отступ в мягкой табуляции фактически представлен определенным количеством обычных пробелов.

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

(далее…)


Информеры с тИЦ и PR: получить код для сайта