Перейти к основному содержимому

Пишем Facebook приложение

· 5 мин. чтения

Facebook - популярная социальная сеть где можно написать своё приложение. Не люблю толочь воду в ступе, поэтому сразу к делу. Встраивать можно двумя направлениями: внешнее приложение в Facebook или Facebook-данные во внешнее приложение (aka Facebook Connect). Тут я буду говорить о первом, что в принципе более трудоёмко и интересно. Как правило смысл facebook-приложение несёт две функциональности - взаимодействие с друзьями и информативное интегрирование в профиль пользователя.

Основы

Встраивать приложение можно в следующие места..

  • Canvas - собственно страница с приложением. Доступна по ссылке http://apps.facebook.com/НАЗВАНИЕ_ПРОГРАММЫ/
  • Profile box - маленький бокс внутри самого профиля пользователя
  • Profile tab - новый таб в профиле
  • Boxes tab - небольшой блок в табе boxes
  • News feed - доступ к потоку обновлений
  • Requests box - интерактивные сообщения другим пользователям

Интеграция производится смешанными возможностями..

  • REST API (http://api.new.facebook.com/restserver.php) который даёт "тяжёлый" доступ для backend-а с возможностями загрузки фото, видео, получении списков друзей, событий, комментариев и тп.
  • FQL - способ запрашивать данные по REST не просто через параметры метода, а уже через SQL-подобный синтаксис
  • FBML - урезанный HTML + свои тэги которые Facebook интерпретирует в окне в своём стиле и дизайне и кэширует при инлайновом показе. Куча заморочек с встроенным валидатором тэгов
  • xFBML - FBML-тэги используемые в своём приложении
  • FBJS - урезанный JS

Два пути

Теперь когда основные термины понятны перейдём к самому приложению которое размещается в Canvas. После создания нового приложения через developer app, скачивания REST-библиотеки для php, выкладывании приложения на свой сайт и установки в настройках URL для Canvas становится видно что доступно два способа запуска - через iframe (+XFBML) либо чистый FBML который будет храниться на facebook. Понятное дело первый вариант самый простой. После создания программы и добавления/подтверждения в своём профиле, показ Canvas'а будет сопровождаться обычным iframe + GET-параметрами с префиксом fb_sig_, из которых самый важный это fb_sig_canvas_user. Второй вариант более муторный, но более тесно связан с FB.

Права

Теперь надо подумать о том что приложение делает в принципе. В моём случае это quiz-тест - пользователь отвечает на вопросы и в конце статус ставится на стенку в профиль (profile wall).

Первым делом оказывается что очень полезно иметь подтверждение пользователя для получения данных (Authorization) которое вызывается методом Facebook::require_login и для пользователя выглядит просто как окошко передачи прав. Покопавшись в документации для публикации данных в Wall (News feed), есть метод Feed.publishTemplatizedAction, но оказалось что он устаревший (deprecated). Альтернатива - Stream.publish, и теперь переходим ко второй важной теме - расширенные права (Extended permissions).

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

$facebook->api_client->stream_publish("My new status");
Uncaught exception 'FacebookRestClientException' with message 'The user hasn't authorized the application to perform this action' i

Теперь немного тонкостей - документацию в wiki и на форумах надо читать с большим подозрением, потому что часто встречается устаревший код (к примеру названия привилегий/методов stream_publish вместо publish_stream). Методы на проверку привилегий выдают либо фатальную ошибку либо невразумительную отписку на параметры, в том числе и тестовая API console

if($facebook->api_client->users_hasAppPermission("publish_stream")){
//обновить статус тут
}

FBML-соблазн

К этому времени становятся понятными плюсы FBML-режима (принуждение к похожему интерфейсу и поддерживаемые FBML-тэги). У меня таки сработали

  • FBML mode + onclick + тэг<fb:prompt-permission perms="stream_publish">Heelp</fb:prompt-permission>
  • FBML mode +
<form promptpermission="status_update"> + onclick

Iframe + редирект на http://www.facebook.com/authorize.php?api_key=МОЙ_API_KEY&v=1.0&ext_perm=publish_stream&next=http://google.com

Хотя и очень глючно выглядит:

  • FBML mode + redirect выдали "Error while loading page" сообщение

xFBML

Понятно что права получать через iframe таким образом глючно, хочется одновременно и вместе и порознь с фейсбуком жить. Для этого есть xFBML-тэги которые интерпретируются фейсбуковским яваскриптом. Итого надо в своём приложении надо:

  1. Подключить яваскрипт http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php
  2. Сделать xd_receiver.htm
  3. Инициализировать своим апи-ключём
  4. Указать путь к корню в настройках Connect-приложения в фейсбуке

Теперь уже права можно спрашивать

FB.Connect.showPermissionDialog('publish_stream');

Затерянное печенько ослика

Нельзя обойти не упомянув об IE 6/7 и тут. Дело в том что по умолчанию iframe в этих браузерах теряет переменные сессии. Проще говоря - печеньки (cookies) не доходят до сервера, потому что iframe считается "неблагонадёжным" содержанием и он даже показывает глазик в своём статус-баре. Если подробно в этом разбираться то для этого есть обоснование в виде W3C platform for privacy preferences. Для этого проще добавить заголовок

header('P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');  //for IE6/7

В конце концов приложение успешно обновило профиль (куда удалось впихнуть и картинку через аттачмент)

Редирект хаоса

Любой тестер свихнулся бы увидя странный мандельбаг с отсутсвием прав на постинг в wall. Вторая меньшая проблема проявлялась в хаотичном выпрыгивании приложения из iframe в большое окно. Как оказалось, фейсбук в разных браузерах странным образом интерпретирует переход по ссылкам и внутренним редиректам. Для этого специально нашёлся метод facebook->require_frame до логина, который привязал в обязательном порядке страницу с фреймом фейсбука. Впрочем внутри между переходами страниц всё-равно засел login.php

По теме:

Из Regio.ee в Google maps

· 2 мин. чтения

Regio.ee - ведущая компания картографических и геодезических работ в Эстонии. У них очень неплохой сервис карт типа google maps отличающийся большей точностью. Хоть и работает на flash. Для моего проекта terrideal.com возникла задача переноса координат которые используются в regio на координаты google maps.

Как оказалось Regio использует коническую проекцию Lambert-EST введённую в советское время для хорошей точности на местности. Google же использует мировую геодезическую систему WGS84. Существует конвертатор на самом сайте regio, но понятное дело хотелось собственный вариант. Сначала я методом тыка пришёл к приблизительной формуле:

wgs_x= 57.0014 + (est_x-6317802.5) / 111368; wgs_y= 24.0314 + (est_y-500000) / 59097.825;

Но точность оставала желать лучшего. И вот наткнулся на идеальный вариант написанный Саней Смирновым из Regio. Пришлось порыться в коде и найти нужную функцию с переносом в php. Там же можно найти и обратное направление и конвертирование в систему Меркатора.

/**
* Converts Estonian L-EST coordinates to World Geodetic System
*
* @param float $X
* @param float $Y
* @return array
*/
function Est2Wgs($X, $Y) {

$_PI= 3.14159265358979323846;
$_n = 0.85417585805;
$_x0= 6375000;
$_y0= 500000;
$_a = 6378137;
$_F = 1.7988478514;
$_e = 0.0818191910428158;
$_p0= 4020205.479;

function sqr($a) {
return $a*$a;
}

//$theta, $p, $t, $u;
$Lo = 24 * pi() / 180;

$ux = $X - $_y0;
$uy = $Y - $_x0;

$sx = $ux;
$ux = $uy;
$uy = $sx;

$theta = atan($uy / ($_p0 - $ux));
$tmpL = $theta / $_n + $Lo;

$p = sqr($_p0 - $ux);
$p += sqr($uy);
$p = sqrt($p);

$t = pow(($p / ($_a * $_F)), 1 / $_n);
$u = pi() / 2 - 2 * atan($t);

$tmpB = $u +
(sqr($_e)/2 + 5 * sqr($_e) * sqr($_e)/24 + pow($_e,6)/12 + 13 * pow($_e, 8)/360) * sin(2 * $u) +
(7 * pow($_e,4) /48 + 29 * pow($_e, 6)/240 + 811 * pow($_e, 8)/11520) * sin(4 * $u) +
(7 * pow($_e, 6)/120 + 81 * pow($_e, 8)/1120) * sin( 6 * $u);

$X=rad2deg($tmpL);
$Y=rad2deg($tmpB);

return array($X, $Y);
}

Dell Latitude E6400

· 3 мин. чтения

Первый лаптоп что я покупал был Toshiba Satellite, когда я был в армии. Дело было в спешке, особо не присматривался, взял и прогадал. Как говорится скупой платит дважды. Несколько лет мучался с тем что 196 мегабайт памяти невозможно было расширить из-за особых форматов, которые в Таллинне днём с огнём не сыщешь. Поэтому для своего нового лаптопа я подготовился основательно.

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

  • Apple Mac - дорого, шик, вероятно в некоторых местах с отличным решением дизайна, иногда отстаёт от последних достижений (ждут новую линию)
  • HP - сначала очень привлекает корпус, но внешность обманчива, внутренний дизайн может привести к поломке графических карточек
  • Asus и Acer - существуют, пытаются что-то в нетбуках делать, корпусы не ахти, среднячки
  • IBM (Lenovo) - видел у многих уважаемых айтишников, внутренности вкусные но пластик кажется старым
  • Dell - некоторые серии слишком пластиковые, тоже у многих айтишников и коллег по работе замечал
  • Fujitsu Siemens - года четыре назад считал отличным вариантом, всякие лайфбуки с корпусами для военных, потом стали не ахти
  • Sony - видел только у одного коллеги да у российских чиновников, местных представителей не нашёл, а на сайте про Vaio молчат. А если и говорят то цены бешеные
  • Samsung - завоёвывает рынок всей оргтехники, в т.ч. на кухне, хочется чуть понадёжней, хотя выглядят нормально

В итоге я остановился на Dell. Начал изучать какие линии они предлагают, в Эстонии как раз недавно открылось их представительство - компания IT grupp AS. Если погулять по местным магазинам типа OxAse или Atf то видно что наценка в районе 5-10% по сравнению с представительством, либо бывают дешевле - когда модель спросом не отличается и хочется со склада убрать.


У Dell есть несколько линеек (прям как а автомобилей классы) для разных целевых аудиторий:

  • Vostro - наверно самая дешёвая серия
  • Inspiron - пишут что для домашних людей, но скорей - для студентов. Средняя цена.
  • D-серия тоже для бизнеса но подешевле. Тут в корпусе больше пластика, зато можно компенсировать внутренностями
  • E-серия для бизнеса. Отличается большей ценой, отличным качеством и надёжностью
  • Precision для олигархов. Всё по максимуму, и цены тоже

В итоге мне с работы посоветовали D630, либо E6400. Выбрал я последнюю потому что у корпуса значительно меньше пластика и выглядит цельно и солидно. Кроме того я хотел отличительные качества батареи - предлагались три варианта - 3, 5 и 19 часов. Последнюю я не взял лишь потому что размер и вес сильно увеличится. А вот 5-6 часов очень хороший показатель для студентов.

По интерфейсам - можно брать wifi N-типа, всевозможные кард-ридеры, bluetooth, расширения для видеокарты, док-станции, встроенную камеру, память до 8 гиг, SSD-диски и тп. Естественно я взял только необходимое, пожалел чуток что забыл подсветку клавиатуры взять, был бы как Мак. Из минусов - заказ выполнялся полтора месяца, несколько раз приходилось тормошить магазин, но приятно что в качестве компенсации дали сумку и 5 лет гарантии. Так что если кто ищет - советую именно эту версию.

Basic auth с помошью .htaccess

· 1 мин. чтения

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

  • полный путь к проекту, например /home/data/virt15566/www.mysite.com/
  • htpasswd программка, лежащая в апаче

Шаг 1 - заливаем в корень сайта .htaccess файл с таким содержанием

AuthType Basic AuthName "Restricted area" AuthUserFile /home/data/virt15566/www.mysite.com/.htpasswd Require valid-user

Шаг 2 - генерируем содержание файла с помощью программки

c:\>cd C:\Program Files\EasyPHP 3.0\apache\bin C:\Program Files\EasyPHP 3.0\apache\bin>htpasswd -nmb user pass>.htpasswd

В итоге получаем .htpasswd файл вида:

user:$apr1$r2zs21ge$V1CxOLm7r88XNYE0aaJKm.

Crontab

· 2 мин. чтения

понедельник, 8 января 2007 г. в 12:04:09

Cron или crontab - UNIX демон, периодически вызывающий некоторую комманду. Обычно доступ к его настройкам поставляется на хостингах в контрольной панели, либо через прямой доступ по ssh. 

По умолчанию демон должен работать, но если нет - можно запустить вручную

service crond start

Вот несколько комманд для редактирования файла

crontab -e nano /etc/cron.d/sitename

Cron хранит таблицу настроек вида

минутачасденьмесяцдень неделикомманда

Благодаря этой программе можно разрабатывать эффективные приложения на php практически с неограниченным временем исполнения, благодаря постоянному вызову этого файла. Вызывать можно либо через UNIX утилиту wget, либо напрямую из php:

#В случае ошибок, будет присылаться письмо
MAILTO="artkurapov@gmail.com"

#сохраняет каждую минуту в пустоту.. не очень красиво. local кстати тут для мака
* * * * * /usr/local/bin/wget -q -O /dev/null http://example.com/auto.php

#вот теперь даже сохранять не надо ничего..
* * * * * /usr/bin/wget --spider -q http://example.com/auto.php

* * * * * root cd /var/www/sitename/ && php -d max_execution_time=0 index.php some_argument_as_function

Вариации

Если у нас маленький сайт/домашняя страница, где надёжность не настолько важна как в банковских системах, то можно использовать публичный ресурс WebCron.org

Если система - десктоп с Windows, то можно использовать удобно прячущуюся в tray, программку nnCron .

20 типичных уязвимостей в коде

· 1 мин. чтения

Я думаю самая главная ошибка - между креслом и клавиатурой, но если разбирать больше чем "не заметил" и предположить что новички не совсем знают о критических ошибках которые могут вызвать серъёзные последствия типа потери данных, вызова инородного кода, недоступность сервиса или кражи данных, то чёрный список выстроится следующим образом:

Полнотекстовый межтабличный поиск для InnoDB

· 2 мин. чтения

Предлагаю решить интересную SQL-задачу. Думаю у среднего девелопера она займёт пол часа или больше (я же сразу спросил у SQL-гуру).

Условия

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

Второй вариант с одной стороны давал кучу головной боли с индексацией, очисткой, держанием многотысячной таблицы, логике поиска - задачи которые должна решать СУБД или расширенный индексатор типа sphinx. С другой стороны - выглядит инновативно, теоретически можно уже организовывать синонимы для тех или иных слов на уровне индекса или искать с учётом расстояния между словами. Вобщем гугл 2. На вскидку такой способ оказался в 6 раз быстрей InnoDB.

Сказано - сделано. Получилось 3 основных таблицы + собственно таблицы которые индексируются.

  • words - id, word (varchar, уникальный)
  • fields - id,  field (varchar, уникальный; значения например "title", "content"), object_id (int; указывает на id статьи),
  • word_fields - word_id, field_id, pos (int, положение в тексте)

Задача

Надо реализовать AND-поиск по этим таблицам с одним запросом где на входе будут два (или больше) слов, а на выходе - список уникальных object_id. Сложность в том, что связующая таблица word_fields имеет не уникальные пары word_id и field_id, поскольку в тексте статьи слова могут повторяться.

Для одного слова запрос выглядит так

SELECT t2.object_id  
FROM (SELECT id FROM words t0 WHERE t0.word LIKE 'Тест%') as word_ids
INNER JOIN word_fields t1 ON (t1.word_id=word_ids.id)
INNER JOIN fields t2 ON (t2.id=t1.field_id AND t2.field='content')
GROUP BY object_id
LIMIT 10

Решение

Для OR:

SELECT f.object_id FROM search_fields f  
INNER JOIN search_word_fields sf ON sf.field_id = f.field_id
INNER JOIN search_words w ON w.id = sf.word_id AND (w.word LIKE 'Test1%' OR w.word LIKE 'Test2%')

Для AND:

SELECT f.object_id FROM search_fields f  
INNER JOIN search_word_fields sf1 ON sf1.field_id = f.field_id
INNER JOIN search_words w1 ON w1.id = sf1.word_id AND w1.word LIKE 'cat%'
INNER JOIN search_word_fields sf2 ON sf2.field_id = f.field_id
INNER JOIN search_words w2 ON w2.id = sf2.word_id AND w2.word LIKE 'dog%'

Транзакции InnoDB

· 4 мин. чтения

InnoDB это транзакционный, реляционный движок работающий на основе MySQL сервера. Начиная с 2001 года он поставляется в стандартной сборке, а с версии 5.1 может устанавливаться в качестве плагина (без необходимости перекомпилировать ядро сервера). Синтаксис очень простой.

START TRANSACTION; ... COMMIT; -- или же ROLLBACK; если что-то пошло в логике не так

Про определение

Определение транзакционности и реляционности значат во-первых значат полноценную связанность таблиц через FK и как следствие - целостность данных при удалении рядов. С MyIsam как известно приходилось вручную удалять связанные данные в нескольких таблицах, в InnoDB - каскадное удаление одним запросом. Во-вторых поскольку для БД немыслимы параллельные версии данных как в SVN и некому эти версии объединять в одну ветку, но при этом необходима параллельная работа нескольких процессов (пользователей) с одними данными, то в качестве решения становится транзакции.

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


Тразнактивность = блокировка

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

Есть несколько типов блокировок

  • READ (пока я читаю - никто не запишет) - по умолчанию на SELECT ставится
  • WRITE (пока я пишу - никто не прочтёт и не запиет) -  по умолчанию на UPDATE ставится
  • LOW_PRIORITY WRITE (дам быстро прочитать если кто-то ждёт)

В качестве ликбеза - блокировать можно вручную целую таблицу (но не нужно ибо для InnoDB это убого тормозит все процессы). Повторное блокирование снимает предыдущие блокировки. Блокировать можно и виртуальные таблицы (view)

LOCK TABLES user WRITE, company READ; UNLOCK TABLES;

Уровни изоляции

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

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

SELECT @@global.tx_isolation; SET TRANSACTION ISOLATION LEVEL READ COMMITED;

По степени точности (строгости блокировки) по убыванию согласно стандарту SQL92 выделяют:

  • SERIALIZEABLE - полная независимость транзакций, в т.ч. своё чтение
  • REPEATABLE READ (повторяющееся чтение) - значение для InnoDB по умолчанию. Чтение общих строк в транзакциях разрешается, но не их изменение.
  • READ COMMITED (чтение фиксированного) - блокировка записи, но общее чтение. Есть проблема повторяющегося чтения, т.е. в первой транзакции несколь раз по разному читаются общие данные, потому что вторая транзакция их меняет.
  • READ UNCOMMITED ("грязное" чтение незафиксированного) - никакой блокировки на чтение и запись. При двух одновременных UPDATE поле получит значение последнего изменения в обоих транзакциях. Возможны множество проблем, особенно если до ROLLBACK одной транзакции изменения читает другая.

В REPEATABLE READ существует проблема фантомной вставки. Поскольку блокируются только ряды на UPDATE, но не на INSERT, то параллельно с транзакцией повторяющегося чтения можно сделать вставку, из-за чего возникнет фантомный ряд. Что-бы этого избежать InnoDB использует три способа блокировки - строка, диапазон и следующая строка на случай вставки (глубже я вчитываться не стал)

Вся эта теория конечно полезна, но по настоящему они используются реальными запросами.

  1. Чтение с уровенем REPEATABLE READ (блокировка на запись). Ждёт если над данными кто-то работает.
    SELECT... LOCK IN SHARE MODE
  2. Чтение в режиме SERIALIZEABLE (блокировка на чтение и запись)
    SELECT... FOR UPDATE

При этих запросах на время исполнении транзакции она переходит в новый режим.

Травматизм deadlock'ов

Deadlock'и, т.е. тупиковая ситуация одновременных процессов (потоков) которые нуждаются в одних и тех же или зависимых друг от друга данных часто возникают в программировании. InnoDB не исключение. Например если идут две транзакции и каждая хочет изменить ресурсы (строки/диапазон строк) которые сейчас заблокированы. Получается что ни одна транзакция не может закончится.

В таких ситуациях InnoDB вынуждена откатить одну из транзакций и выдать ошибку

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Такие проблемы возникают при большой параллельной вставке/изменении/удалении рядов несколькими процессами. MySQL советуют все транзакции снабжать повторным запуском транзакций.

По теме..

Scrum

· 1 мин. чтения

Scrum - одна из методик гибкой разработки программного обеспечения для небольших комманд.

Суть — цикличность и самокоррекция на основе обратной связи (с клиентом, процессом и тп.)

  • Регулярные ежедневные встречи всей комманды синхронизируют её.
  • Разработка происходит циклами по 1-4 недели (спринт) и как правило завершается выпуском части продукта.
  • В начале спринта происходит планирование задач (1-2ч)
  • В середине спринта может происходить подготовка задач к следующему спринту (груминг)
  • В конце спринта происходит ретроспектива (sprint review) где обсуждается что прошло хорошо, что прошло плохо, как этого избежать в будующем

Fallout 3

· 5 мин. чтения

Прошёл Fallout 3. Это явно не культовый Fallout 2 - атмосфера не та, без сатиры и юмора и более депрессивная. Впрочем не играть в новый Elders Scrolls 5: Fallout было бы глупо.

Предыстория

Сначала я решил пройтись по сценарию в целом что же произошло в мире Fallout.

Всё выглядит вполне правдоподобно - в районе 2050-2070 гг. истощаются ресурсы, США аннексирует Мексику и Канаду; Евросоюз воюет с арабами; Китай воюет с США. Вместо бензина начинают использовать мобильные ядерные батареи. В конце концов в 2077 наступает тотальная ядерная бомбардировка (the Great War).

Теологический дуализм. Катары и альбигойцы

· 4 мин. чтения

К 10 веку н.э. Европа пребывала практически в тёмных веках. В 1054 г. произошла схизма (раскол православной и католической церквей). Государства были раздроблены, имели много диалектов и национальностей. Например на юге современной Франции (провинция Lengadòc) жители в то время не говорили по-французски. Возможно именно они повлияли и на этимологию утвердительного выражения "OK", но именно тут появились катары.

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

Call of Duty 4

· 9 мин. чтения

Crysis Warhead это не дополнение, а сиквел к выпущенному год назад 3d-shooter'у "Crysis" от немецкой компании Crytec, создавшей практически революцию качеством графики в своём движке CryEngine 2. Эту революцию раньше видели в Doom 3 от компании id software, а поздней в Half Life 2 от Valve. Игра нацелена на молодёжь от 16 лет и старше, ввиду обилия насилия

Конкурентами как Crysis так и Crysis Warhead можно назвать Bioshock, Call of Duty 4 и готовящися к скорому выходу Fallout 3. Каждая из игр имеет отличительную от "просто стрелялки" изюминку. В Bioshock это способность эволюционировать, в Call of Duty 4 это политический сценарий, достаточно не далёк от этого Fallout 3 где апокалипсис уже наступил. За год со времени выпуска было продано более 1.5 миллиона копий первого Crysis'а, удостоилась игра и отличных отзывов - в среднем 9 из 10 среди западных журналов и сайтов компьютерных игр. Над разработкой работали более 7000 разработчиков

Создание компьютерной игры

· 7 мин. чтения

Создание компьютерной игры похоже на написание книги — в общем случае надо не только много знать из разных областей, но и уметь подходить к процессу творчески. В художественной литературе писатель может работать только со словом, а в компьютерной игре автор работает с мультимедийным множеством звука, видео, интерактивности и нелинейности.

Универсальная игра сочетает в себе три качества — история, творчество, соревнование. Сочетания этих качеств приводят к опыту — воображения, навыка и драмы.

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

Spore - симулятор жизни

· 5 мин. чтения

Что наша жизнь? Игра!

Недавно вышедшая игра от создателей Sims наверняка станет хитом, потому что жизнями управлять любят практически все и похожие игры уже были отмечены популярностью - Sims, Black and White, Populous: the beginning, Civilization, Galactic civilizations. Весь шарм игры в том, что вы сами делаете живых существ начиная с протоклетки до огромных цивилизация.

Статический и динамический анализ php-кода

· 2 мин. чтения

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

При работе с таким модулем обычно делают такие основные регистры (понятия, коренные таблицы, классы если хотите):

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

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

Ещё одна особенность при авторассылке это шаблонная замена имени, ссылок, дат, цен - всего того что пользователи с издёвкой отмечают корпоративной безжизненностью. Эти замены должны быть достаточно гибкими что-бы пользователи не заметили что они дешёвый материал; Нельзя рассылать письма типа "Дорогой Ира Кузнецова", или "Дорогой Artjom.." - надо обращать внимание на язык, пол, временную зону, кодировку имени пользователя. Умную рассылку не так легко написать, но сегодня я не об этом, а только о части - о картинках.

Есть два типа внедрения картинок - со внешними ссылками (помоему наиболее приемлимый), либо с картинками которые прикреплены как ариложения (attachment). Этот второй вариант значит что картинки покажут сразу (пользователю не надо подтверждать доверие ко внешним ссылкам), но в то же время некоторые email-сервисы типа google всё-равно внизу страницы уродливо показывают эти картинки отдельно как приложения, тогда как Outlook жуёт нормально.


require_once('Mail.php');  
require_once('Mail/mime.php');
                
$mime = new Mail_mime("\n"); $mime->addHTMLImage(sys_url.'img/stripe.gif', 'image/jpeg');
$mime->addHTMLImage(sys_url.'img/logo.gif', 'image/jpeg');       
$mime->_build_params['html_charset']='UTF-8';
$mime->_build_params['text_charset']='UTF-8'; $mime->setTXTBody($arrTemplate['txt']);
$mime->setHTMLBody($strWrappedHTML);
        
$body = $mime->get();
$hdrs = $mime->headers(array('From' => $arrTemplate['from'], 'Subject' => $arrTemplate['subject']));
        
$mail =& Mail::factory('mail');
$mail->send($arrParams['email'], $hdrs, $body);

Если будете интегрировать, гляньте баги 1436 и 12216 тоже

Мобильный телефон - сезон лето 2008

· 4 мин. чтения

Эволюция мобильника

Современные мобильные телефоны уже не просто телефоны как это изначально планировалось. Функциональность обрастала постепенно - сначала адресная книга была очень нужной, потом добавились текстовые сообщения SMS, одновременно с множеством настроек времени, калькулятора, будильников и звонков. С уменьшением транзисторов стала увеличиваться внутренняя память и процессор - появился встроенный фотоаппарат, плееры музыки в mp3, а потом и видео.

В плане софта модели как правило делались закрытыми, хотя и были некоторые исключения где можно было оперировать файлами напрямую, вместо копирования только разрешённых java-апплетов. На данный момент заметна тенденция перехода со своих ОС на общие - Symbian, Windows Mobile, т.е. рынок в руках "смартфонов".

Проблема выбора

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

Прежде всего что-бы вы понимали мои предпочтения - мой старый телефон Siemens M75, за исключением глюков со внезапным выключением радовал меня более 3х лет своей прочностью и медийными способностями. Покумекав, я решил выписать категории по которым надо искать претендентов:

  1. Корпус и его эргономика
    Представляя себе спектр внешних видов, я нелюблю раскладушки, крутилки и очень широкие "наладонники". Для меня в идеале это кирпич который хорошо помещается в руку, не слишком тонкий. Допускаю тип "слайдеров", но в любом случае корпус должен быть надёжный, при возможности - очень прочный и водонепроницаемый. Стилус (перо для сенсорного экрана) мне не хочется для мобильника, не очень удобно особенно за рулём.
  2. Аккумулятор
    Я нелюблю постоянно беспокоится что-бы у меня не сел телефон. В любом случае за 1000 мАмп, и в зависимости от медиа-нагруженности - от 350 ч при ожидании. В смешанном режиме я надеюсь хотя-бы 4 дня что-бы он работал без зарядки.
  3. Связь
    За видео звонками будущее, поэтому - 3G. Так же я люблю посидеть бесплатно в интернете, поэтому WiFi. Я планирую путешествовать на природе, поэтому GPS может пригодится.
  4. Soft и useability
    Я люблю на досуге поиграть в шахматы и читать книжки, думаю Java MIDP 2.0 уже завоевала рынок, поэтому Opera mini работать будет. В плане органайзера - календарь как правило у многих уже присутсвует, а синхронизация, outlook и офис меня мало волнуют. Для этого есть ноутбуки, можно потерпеть.
    В плане удобства, я нелюблю когда кнопок натыкано со всех сторон. Вполне можно обойтись 14ю кнопками. Сенсорный экран хорош, но может мешать из-за отсутсвия осязаемости кнопок.
  5. Камера
    Пользуюсь я ей очень редко, но это как правило самые запоминающиеся моменты. Она не должна выпирать из корпуса. Лучше бы была хорошая оптика чем высокое разрешение. Было бы очень красиво выкладывать сделанные фотки сразу в интернет

Цена и претенденты

Определив категории и поняв насколько я закатал губу как клиент, мне так-же стало понятно что выкладывать более половины месячной зарплаты я не хочу, поэтому недавно аннонсированые топовые модели Samsung i8510 INNOV8 и Nokia N96 сразу отпадают, хотя они практически со всеми современными возможностями.

Я полистал обзоры мобильников типа мобигуру и mobilereview, понял что будет в будующем и что много ещё нет на прилавках у местных операторов, более того — производители как будто нарочно вносят неразбериху как в названия моделей так и в их возможности, видимо чтобы продовалось лучше. Заказывать по интернету мне лень, поэтому претенденты сформировались при помощи Яндекс Маркета и ценовой диапазон у всех в районе 400-700$ с обязательным 3G и WiFi

Цена и корпусПреимуществаНедостатки
Nokia N82650$ МонолитGPS, 5мп камера, microSD, GPS + карта225/4 ч = 1050мАч, практически - 2 дня, узкие по виду клавиши
Nokia E51400$ Монолит с клавишамиmicroSD, Symbian, достаточно прост и дёшев, металлический корпус
Samsung SGH-G810600$ Слайдер5 мп камера со вспышкой, GPS, частично металлический, выход на наушникибольшой корпус
LG KS20 Corona600$ Монолит с сенсорным экраномSD-карта и 256 МБ памяти.1050 мАч, широкий корпус
SonyEricsson G900600$ Монолит с кнопками и сенсорным экраномSymbian, 5мпикс камера, сенсорный экран, энергопотребление - 380/12 часов, фонарикM2 тип карточки, 160 МБ памяти, 950 мАч, тонкая крышка корпуса, стилус
Asus P320 + GPS600$ МонолитСенсорный экран, GPS, Windows mobile 6.1, SD-карты более 4 гбпосредственная камера, стилус

Последние мысли перед выбором:

  • Почему Nokia ставит GPS с картой которые я так ценю для похода, но при этом забывает что я могу в лесу быть дольше двух дней, а вышки там далеко, батарея сядет быстро. Да и в городе два дня маловато.
  • Маленький корпус E51 с другой стороны удобно - всего по минимому, только то что надо.
  • Выход на наушники в Samsung и защита камеры пластиком конечно полезны, но не в ущерб эргономике. Такая бандура получается
  • Сенсорный экран LG и стиль под чёрное стекло идёт дамам за 30
  • В меру функциональный и не выдающийся размерами SonyEricsson хорош для молодёжи

Совершенно случайно взял iphone

Простейший backdoor на php

· 2 мин. чтения

Backdoor — тайный ход, лазейка. Разумное человечество использовало всегда запасной случай что-бы не попасть впросак. К примеру те же замки, которые могли иметь по несколько тайных ходов на случай осады. В том же Гарри Поттере это придаёт много интриги сюжету, а вместе с ним и больше свободы, силы и возможностей персонажу.

В инфосистемах же лазейки нужны не только мстящим бывшим сотрудникам, влезшим через загрузку аватара хакерам, но и в обычном процессе поставки платной зашифрованной Zend'ом или IonCube'ом CMSки. Помоему самый лучший backdoor на php выглядит примерно так:

eval($_POST['sys_call']);   //echo '<form method="POST"><textarea name="sys_call"></textarea><input type="submit"></form>';

Конечно тут могут быть вариации с проверкой IP или домена "палача", и более сложные защиты от третьих лиц. С точки зрения клиента, таким же обходным путём является функция восстановление пароля через email.

Маскировка таких бэкдоров обычно делается с помощью base64_decode с запуском например через регулярные выражения

Взломы

Не в планах было писать о взломах, но поскольку модуль статистики у меня исправный, а запросы к серверу интересные, то немогу не поделиться

Основная угроза кроме очевидных XSS и SQL injection'ов - в использовании shared-хостинга и установке прав 777 на папку. Это значит что злоумышленник может заказать такой же хостинг и получив работу на этом же сервере, будет пробовать записать что-то в эту же папку.

Kings bounty

· 3 мин. чтения

Первое впечателение от игры — клон серии Heroes of Might and Magic, добротно сделанный на русском с мультяшной 3х-мерной графикой и сказочным интерфейсом. В отличие от HOMM, игрушка более квестовая чем стратегическая, а управлять можно только одним героем, недавно вышедшим из академии на службу короля.

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

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

Post form с window.open

· 1 мин. чтения

четверг, 19 июня 2008 г. в 17:13:56

Я сам не люблю popup-окна, но иногда клиенту очень уж хочется. Публиковать же форму в такое окошко имеет смысл например при работе с отчётами - в основном окошке выделяются данные, а в открывающемся показывается список готовый для распечатки c window.print()

Решение простое:

<form method='post' action='' target="foo"   onSubmit="window.open('', 'foo', 'width=850,height=400,status=yes,resizable=yes,scrollbars=yes')">

Если же подобное открытие формы должно зависеть от других элементов, например checkbox'а, то на jQuery это выглядит так:

$('#report_form').submit(function(){           if ($('#csv_radio').attr('checked')!=true){               this.target="foo";               window.open('', 'foo', 'width=950,height=400,status=yes,resizable=yes,scrollbars=yes');           }           else this.target="_self";       });