вторник, 18 октября 2016 г.

Как развернуть Node.js приложение на рабочем сервере с ngnix? PM2 спешит на помощь!

Итак, предположим что вы уже умеете запускать node.js приложение =), т.е. выполнить команду примерно такого вида, для вас не составит особого труда:

$: NODE_ENV=develop node --harmony api.js -p 8080

тут, кто не в курсе:

  • NODE_ENV: передаем переменную окружения в процесс node.js где он будет
    доступен таким образом, process.env.NODE_ENV
  • api.js собственно ваш файл приложения
  • -p 8080, а это уже параметр непосредственно передаваемый в ваше приложение

Запустить получилось, все хорошо, работаем потихоньку, разрабатываем. Впринципе, устраивает. Но вот пришла пора выпускать свой зверь-сервис в жизнь, так сказать, поселить его надобно на сервере добротном. Да так чтобы работал не покладая сил :). Т.е. без демонизатора не обойтись, а где его взять удобный и понятный, мало кто знает. Я тоже не знал, пока не наткнулся на замечательный менеджер процессов, написанный на нашем любимом JavaScript и node.js, речь пойдет о PM2.

Pm2 это хороший менеджер процессов. До недавнего времени работающий только
с нодой, но теперь он поддерживает скрипты написанные на разных языках и технологиях.
Из основого что он может:

  • Автоматический перезапуск упавшего приложения, из-за криво написанного обработчика ошибок :) или фатальной ошибке.
  • Использование кластерного мода, т.е. будут использованы все ядра CPU для работы приложения, чего не делает сама нода.
  • Удобный деплой
  • Логирование происходящего
  • Умение перезапустить приложение в случае изменения файлов, это штука удобна при разработке,
    но я использую Idea и подружить её дебаггер с pm2 вотчером не вышло. Пока... не вышло.

Для установки pm2 выполните эту "сложную" команду :)

npm i -g pm2

Все теперь можно попробовать запустить ваше приложение

pm2 start app.js
    // или со слежкой изменения файлов, т.е. будет атворестар в случае изменения файлов
    pm2 start --watch

pm2 выведет информацию о запущенном приложении

┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬──────────┐
│ App name │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼──────────┤
│ app      │ 0  │ fork │ 7263 │ online │ 0       │ 0s     │ 0%  │ 15.6 MB   │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴──────────┘

По "App name" можно обращаться к приложению или по его "id", давайте попробуем перезагрузить его

pm2 restart app
  // или
  pm2 restart 0

Для остановки необходимо выполнить эту команду:

pm2 stop app

Можно вообще удалить прилоджения из менеджера для этого выполните

pm2 delete app

Логи (логи будут показывать в режим "онлайн")

pm2 log app

просмотреть состояние приложений можно командой

pm2 monit
  а для конкретного приложения
  pm2 monit app

Небольшая шпаргалка с командами Pm2

Так, управлять процессом это уже хорошо, но как управлять процессом автоматически? Для этого все что необходимо, можно сконфигурировать в файле, и "скормить" этот файл pm2

Создадим в корне проекта, рядом с package.json новый файл конфигурации для pm2 process.json с таким содержимым.

{
  "apps": [
    {
      "name"       : "api-app", // Название приложения, по этому названию будет проще искать и работать с ним через Pm2
      "script"     : "./api.js", // Исполняемый файл приложения
      "args"       : "-p 8080", // Аргументы для вашего приложение (не путать с параметрами интерпритатора node.js) можно указывать массивом, например так: ['-p', '8080']
      "node_args"  : "--harmony" // Параметры интерпритатора node.js
      "exec_mode"  : "cluster", // Режим работы Pm2
      "instances"  : 4 // Количество процессов для запуска, проще: сколько ядер, столько и ставим.
    },
    {
      "name"        : "worker", // Это второе приложение в одном конфиге
      "script"      : "./worker.js",
      "watch"       : true, // это тот самый параметр, который заставит следить за изменениями файлов, и в случае изменения перезапустит приложение
      "env": {
        "NODE_ENV": "development", // Переменные окружения, которые будут добавлены по-умолчанию если при запуске не указан параметр env
        "DEBUG": "*"
      },
      "env_production" : {
         "NODE_ENV": "production" // Переменные для prodcution окружения
      }
    }
  ],
  "deploy": { // Интсрукции для деплоя ваших приложений, которые описаны выше
    "production": {
      "user": "node", // Имя под которым вы будут авторизоваться по SSH на серверах для деплоя
      "host": ["212.83.163.1", "212.83.163.2", "212.83.163.3"], // сервера для деплоя
      "ref": "origin/master", // Ветка для выгрузки
      "repo": "git@github.com:repo.git", // Ссылка (или путь) к репозиторию
      "path": "/home/project/api", // Путь на сервере к расположению проекта
      "post-deploy": "npm install; pm2 startOrRestart process.json --env production", // После отработки деплоя выполнит эти команды в корне выгруженного проекта
      "env": {
        "NODE_ENV": "production"
      }
    },
    "test": {
      "user": "node",
      "host": "212.83.163.3",
      "ref": "origin/develop",
      "repo": "git@github.com:repo.git",
      "path": "/home/project/api",
      "post-deploy": "npm install; pm2 startOrRestart process.json --env production"
    }
  }
}

Запуск через кофигурационный файл можно осуществить так:

pm2 start process.json

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

ssh-keygen -t rsa -f /path/to/file

Затем копируем публичный ключ из /path/to/file.pub на сервер в файл ~/.ssh/authorized_keys

Проверяем авторизацию. Далее, наверняка есть желание проверить этот самый деплой. Запускаем

pm2 deploy process.json production

Тут deploy это команда для запуска процесса деплоя с использованием параметров, указанных в файле process.json а атрибуте "deploy", process.json это наш файл конфигурации, и production это параметр окружения, в нашем случае это production окружение.

Перед деплоем нашего свежего кода, не забываем его пушить в репозиторий, а незабыть нам поможет package.json с его параметром "scripts", добавляем команду:

...
  "scripts": {
    ...
    "release": "git push origin master; pm2 deploy process.json production",
    "testup": "git push origin develop; pm2 deploy process.json test",
  }
  ...

После чего для релиза приложения достаточно будет в корне проекта выполнить команду

npm run release

А для обновления тестового сервера

npm run testup

И небольшая настройка, если вы используете nginx и вы хотите, например, чтобы ваше приложение было доступно по адресу http://zver-project.com/api, то добавте следующее в конфиг nginx к вашему хосту

...
  location /api/ {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-Nginx-Proxy true;
      proxy_pass http://127.0.0.1:8080/;
      proxy_redirect off;
   }
  ...

Я описал совершенно мизирную часть возможностей pm2, он еще много чего умеет. Больше информации можно найти тут на официальном сайте PM2

пятница, 7 октября 2016 г.

Как искать landing страницы?

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

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

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

"Во дела!" подумал я :), надо делать. Надо делать площадку для поиска таких страниц, и дать возможность регистрироваться владельцам таких страниц. Я смогу комфортно искать нужные мне товары, а владелец landing страницы получит дополнительный источник потенциальных клиентов. Неплохо, неправда ли?

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

Так а в чем же суть сервиса Landingbook? Суть проста: человек регистрирует свою лендинг страницу в каталоге, она модерируется и попадает в поисковую выдачу, все!

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

В итоге простенький каталог, похоже, перерастет в очень непростенький поисковичек.

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

вторник, 12 мая 2015 г.

Как установить io.js на Ubuntu

Всем привет! Для того чтобы установить io.js на лучшую в мире ОС :) надо обладать особым складом ума, иметь навыки и ловкость ниндзя. Итак по-порядку:
  • Создадим или перейдем в папку с вашими любимыми бинарниками, например /home/tobi/soft
  • Скачаем архив с оф. сайта, в моем случае это x64 (все доступные для текущей версии 2.0.1)
  • Распакуем и удалим архив
  • Создадим ссылки на бинарники что бы можно было вызвать iojs в любом месте
Ну а теперь понятным языком :)
$: mkdir /home/tobi/soft
$: cd /home/tobi/soft
$: curl -O https://iojs.org/dist/v2.0.1/iojs-v2.0.1-linux-x64.tar.gz
$: tar -xvf iojs-v2.0.1-linux-x64.tar.gz
$: unlink iojs-v2.0.1-linux-x64.tar.gz
$: ln -s /home/tobi/soft/iojs-v2.0.1-linux-x64/bin/iojs /usr/bin/iojs
проверяем установку для пущей правды перейдем в домашний каталог
$: cd ~
$: iojs -v
v2.0.1
Это пожалуй все

понедельник, 24 ноября 2014 г.

Magento. Подчищаем атрибуты, без шума и пыли.

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

<?php
include 'app/Mage.php';
Mage::app();
$setup = Mage::getResourceModel('catalog/setup','catalog_setup');
$setup->removeAttribute('catalog_product','your_attribute_name');

Вместо your_attribute_name вписываете имя удаляемого атрибута. Все! честь спасена.

вторник, 11 февраля 2014 г.

CORS. Как посылать запросы GET, POST, DELETE etc.

В наши дни не знать что такое CORS (wiki), сродни прогулки тёмной ночью по последнему этажу, недостроенной высотки где-нибудь за городом, в неблагополучном районе... Т.е. смертеподнобно, а особенно если вы фронт-енд разработчик.

Более подробно вы можете ознакомиться перейдя по ссылкам в конце текста, я же скажу вкратце, CORS это набор HTTP заголовков, которые позволяют объяснить браузеру и серверу, что они хоть и из разных доменов, но одной крови работать могут вместе. Т.е. кросс-доменные зпросы поддерживаються. Кто не знает, то запрос из браузера посредством старого, доброго JavaSctipt недавно, так на чистоту, без костылей сделать было невозможно. Ура, эти мрачные времена канули в лету. Пришёл на момощь CORS.

Речь пойдет именно о процессе использования и базовой настройки заголовков сервера, и отсыла запросов клиента с использованием jQuery.

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

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

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

Access-Control-Allow-Origin — (обязательный) собственно список разделенный пробелами допустимых доменнов (источников), которые будут ломиться делать запросы к нам на сервер. Из особенностей: регистрозависим, поддерживает маски, например, http://api.superservice.com/, http://*.superservice.com/ или, как вы могли догадаться просто "звездочка" *. Этот заголовок будет сравниваться с заголовком Origin клиентского запроса.
Access-Control-Allow-Method — (обязательный) это список доступных HTTP методов, разделенных запятыми. Особое внимание стоит уделить тому, что "звездочка" аля * работать не будет!
Access-Control-Allow-Headers — (обязательный вместе с Access-Control-Request-Headers) список через запятую заголовков разрешенных в запросе.

Пример настройки для Apache:

# CORS заголовки (добавте это, например, в .htaccess)
<ifmodule mod_headers.c>
  Header always set Access-Control-Allow-Origin: "*"
  Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
  Header always set Access-Control-Allow-Headers "X-Requested-With, content-type"
</ifModule>

Давайте разберемся, что тут происходит? А происходит следующее, запросы будут обработанны с любого источника, если они будут одного из перечисленных в Header always set Access-Control-Allow-Methods типов, так же будут подерживаться заголовки X-Requested-With и content-type

Тот же пример для PHP

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: X-Requested-With, content-type');
?>

Теперь, предположим, что сервис у нас крутится по адресу http://api.superservice.com/ , а GET запрос нам надо сделать со странички http://pure.client.net/. Это не сложно сделать, к примеру с jQuery:

jQuery.ajax({
  url: 'http://api.superservice.com/credit-card-ids',
  type: 'GET',
  contentType: 'application/json', // тот тип контента, который вы будете получать от своего сервиса
  headers: { }, // Разные заголовки, нестандартные заголовки, не забудте их указать в Access-Control-Allow-Headers
  success: function (res) { 
  console.log(res);
},
error: function () { ... }
});

Думаю самое время упомянуть о неприятном моменте с AngularJs если вам понадобиться сделать кросс-доменый запрос с помощью $http или $resource, то надо будет удалить один заголовок, делается это так:

myApp.config(['$httpProvider', function($httpProvider) {
 $httpProvider.defaults.useXDomain = true;
 delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);

Такое поведение странно, для меня, по крайней мере, несмотря на то что заголовок X-Requested-With вы укажите Access-Control-Allow-Headers не исключены проблемы с запросами. Ходят слухи что это бага AngularJs, кому интересно, если найдете что, отпишитесь в коментах.

Переходим к интересным запросам типа POST/PUT/DELETE, всех их объединяет то что они пытаются что-то изменить на сервере. Но как сделать такой запрос кросс-доменным? Сначала надо получить список заголовков типа Access-Control-*, делается это предварительным OPTIONS запросом. Который может вернуть тот же набор Access-Control-*, что и обычный метод GET.

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

Этот предварительный запрос (prefligth-запрос), делается автоматически jQuery или тем же Angular, по-тому же URL что и ваш основной запрос POST/PUT/DELETE поэтому будте внимательны если вы не сделаете правильной обработку запросов типа OPTIONS то и запрос POST/PUT/DELETE у вас сделать не получиться, из-за политики безопасности, который следуют браузеры.

Пример запроса POST с использованием jQuery.

jQuery.ajax({
  ulr: 'http://api.superservice.com/credit-card-ids',
  type: 'POST',
  data: '{"content": "' + content + '"}', // внимание! если вы передатите параметр как объект то это будет Query String, в данном случае это Request Body, т.к. тут передана строка.
  contentType: 'application/json', // тот тип контента, который вы будете получать от своего сервиса
  headers: { }, // Разные заголовки, нестандартные заголовки, не забудте их указать в Access-Control-Allow-Headers
  success: function (res) { 
  console.log(res);
},
error: function () { ... }
});

Я старался изложить кратко, в справочном виде, не очень получилось :), но думаю многим кто прочитал это сэкономит время. Ниже список источников, который позволят вам более глумого изучить вопрос CORS

пятница, 20 декабря 2013 г.

Node.js. Легкий стресс-тест через Phanos.

На волне набирающей популярности ноды. Решил взяться за написание маленького паучка, который бы имитировал реального пользователя. И гулял по сайту не аки бот, а как нормальный человек. Благо в инфраструктуре ноды добра для написания такого чудного существа достаточно. Основа паука стал phantom.js, это "обезгалвленный" движек Webkit, другими словами - это браузер лишенный UI.

Итак, Phanos, в первую очередь мне он был нужен для одной важной задачи, - сымитировать набег пользователей на сайт в течении 2х недель! Самое интересное что для сайт этот был single page application. Т.е. это полноценное web-приложение с кучей асинхроных запросов и всякой джэесины :). Которую как мы понимаем не в состоянии отработать jMeter ни тем более Apache Banchmark. А так как интерес к node.js у меня сейчас в обостренной форме, хотя как мы можем заметить, в рунете заметен спад заинтересованности. То собственно и был рожден сей паучек. Еще одна особенность сайта - это то что он также реализован на node.js и эта штука вся крутится на heroku, то вся статитка также отдается через аппликуху, то так же важно грузить и все остальное, т.е. картинки, стили и собственно Js.

Phanos, его особенности это:

  • имитация посещения пользователями длительное время, т.е. вы можете оставить тулзу работать в течении дня, недели, месяца, да хоть года, указать количество пользователей и вперед.
  • полностью отрабатывает страницы с ajax js
  • легко устанавливается и работает под Linux и Windows, теоретически должен работать и на Mac.

Для начала работы с Phanos необходимо установить node.js. А затем выполнить команду, Ubuntu:

$ sudo npm install -g phanos

для Windows:

$ npm install -g phanos

В процесе установки будет загружен phantomjs под вашу платформу. Ниже приведу пару примеров как пользоваться phanos.

$ phanos -u = http://www.google.com -w 10 -t 3600

Команда выше запустить 10 волкеров (пользователей) "гулять" по гугл в течении 1 часа (3600 сек.). Как лего догадаться то -u это адрес страницы, -w это количество пользователей, -t время работы скрипта, здесь час.

$ phanos -u = http://www.google.com -w 10

Тут просто 10 волкеров в течении 30 сек. будут шнурять по сайту.

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

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


P.S.: Phanos - это симбиоз от слов Phantom и stress, а не то что могут подумать некоторые изощреные умы =)

понедельник, 28 октября 2013 г.

Magento. Операторы сравнения.

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

array("eq"=>'n2610')
WHERE (e.sku = 'n2610')

array("neq"=>'n2610')
WHERE (e.sku != 'n2610')

array("like"=>'n2610')
WHERE (e.sku like 'n2610')

array("nlike"=>'n2610')
WHERE (e.sku not like 'n2610')

array("is"=>'n2610')
WHERE (e.sku is 'n2610')

array("in"=>array('n2610'))
WHERE (e.sku in ('n2610'))

array("nin"=>array('n2610'))
WHERE (e.sku not in ('n2610'))

array("notnull"=>true)
WHERE (e.sku is NOT NULL)

array("null"=>true)
WHERE (e.sku is NULL)

array("gt"=>'n2610')
WHERE (e.sku > 'n2610')

array("lt"=>'n2610')
WHERE (e.sku < 'n2610')

array("gteq"=>'n2610')
WHERE (e.sku >= 'n2610')

array("moreq"=>'n2610') //a weird, second way to do greater than equal
WHERE (e.sku >= 'n2610')

array("lteq"=>'n2610')
WHERE (e.sku <= 'n2610')

array("finset"=>array('n2610'))
WHERE (find_in_set('n2610',e.sku))

array('from'=>'10','to'=>'20')
WHERE e.sku >= '10' and e.sku <= '20'

понедельник, 23 сентября 2013 г.

Git, nodejs-проект и SSH. Установка, разворачивание, запуск в фоне

Итак, поступил заказ на "допиливание" проекта, или же вы купили новый девайс, на котором планируете вести разработку любимого Web-приложения параллельно с основным или надо быстро поднять окружение для разработки на Node.js с уже имеющимся кодом или... Или 1000 и одна причина по которой может резко понадобиться разворачивание проекта на машине. Речь, как можно догадаться из заголовка, пойдет о таких вещах: Nodejs, Git, Ssh. Начнем-с.
В первую очередь оговорюсь, все проделывалось в Debian/Ubuntu системе, хотя немного изменив курс туториала, это применимо и к другим дистрибутивам и даже к Windows :)

  • Ставим Git если его еще нет в системе (для Винды это  вообще очен мажно с ним в придачу можно поставить чудо-юдо MingGW)
    $ sudo apt-get install git
    
  • На всякий случай обновляем репы
    $ sudo apt-get update
    
  • Вот эта штука очень полезная, я про python-software-properties. Она содержит в себе утилиту add-apt-repository и что самое грустое что если у вас сервер Ubuntu то скорее всего у вас ее нет, если десктоп, то можно и не ставить.
    $ sudo apt-get install python-software-properties python g++ make # Ставим зависимости
    $ sudo add-apt-repository ppa:chris-lea/node.js # Добавляем репозиторий node.js
    $ sudo apt-get update # Обновляем репы
    $ sudo apt-get install nodejs # Ставим node.js последней версии
    
  • Далее переходим в директорию в которой будем разворачивать проект
    $ cd /var/www # Эта директория указана для примера и может быть любой другой.
    
  • Далее надо сгенерировать SSH ключ
    $ ssh-keygen -t rsa
    
    Если вы не указывали никакого другого пути для сохранения ключа то вы его можете найти в
    $ ~/.ssh/id_rsa.pub
    
  • Копируем его содержимое и добавляем в сервис (или в ~/.ssh/authorized_key на сервере от куда мы будем тянуть код проекта) например это может быть Github, Bitbaсket, Heroku и др. У меня это Heroku
  • Переходим в папку для проекта у меня это /var/www и клонируем проект
    $ cd /var/www
    $ git clone git@heroku.com:yourproject.git ./
    
  • После чего не забываем установить сопутствующие модули, не думаю что у вас их не будет
    $ npm install
    
  • И если вы хотите "повешать" процесс на "прослушку" 80-го порта, то не забудте это сделать от рута, т.к. мы же все помним что порты ниже 1024 требуют прав рута.
    $ sudo NODE_ENV=staging PORT=80 node app.js
    

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

Итак для того чтобы запустить ноду в фоне надо выполнить следующую команду. Предварительно создайте директорию для логирования вывода процесса, ну, например, /home/macho/logs/ или /var/logs/yourproject

$ sudo npm install supervisor -g # Устанавливаем глобально модуль supervisor
$ sudo NODE_ENV=staging PORT=80 supervisor app.js > /var/logs/yourproject &
Собственно команда выше запустит ноду в фоне и вы можете насладится результатами работы вашего приложения на 80-м порту.
Удачи, надеюсь пост окажет непосильную помощь, в освоении node.js

понедельник, 16 сентября 2013 г.

Nodejs. Как же все таки работать с модулем Async

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

Как полностью устроен принцип работы callback в node.js рассказывать не стану. Просто скажу, что первым параметром колбека всегда должен быть err объект или строка ошибки. Если внутри вашей пачки колбеков (в независимом скоупе есть еще череда колбеков), то у внутренних колбеков можно опустить параметр ошибки, т.к. эта пачка будет "видеть" общий для них объект ошибки, который можно смело передать в "выходной" колбек. Чего-то я какой-то замудренной фигни понаписал :), итак перейдем к инструменту который позволяет немного упростить и привести ваш код к более красивому и читаемому виду - это модуль Async, он позволяет навести порядки в ваших стеках колбэков. Итак приступаем. Первым делом добавляем в ваш package.json новую зависимость: "async": "*", после запускаем
npm install
Или же можно просто сделать так
npm install --global async
Эта команда установит Async глобально в вашу систему и будет доступен во всех проектах. Итак что нам может предложить Async для Node.js? А предложить он может многое стоит заглянуть для полного списка на его страничку github.org,я же приведу примеры для некоторых из них, и только из раздела control flow а именно:

Series — этот метод позволяет выполнять коллекцию задач по-порядку, и на выходе выполнить какой-нибудь полезный колбек. Этот метод полезен когда важен порядок выполнения, если можно так сказать то этот метод позволит вам "победить" асинхронность ноды:
var async = require('async')
  , tasksIndex = [
        function (callback) {
            // Вымышленный метод который вернет 231
            var viewsNumber = models.stat.viewsNumber();
            callback(null, viewsNumber);         
        }
      , function (callback) {
            // Вымышленный метод который вернет 24
            var growFactor = models.stat.growFactor();
            callback(null, growFactor);
        }
    ]
  , taskNamed = {
        viewsNumber: function (callback) {
            callback(null, models.stat.viewsNumber());
        }
      , growFactor: function (callback) {
            callback(null, models.stat.growFactor());
        }
    };

async.series(tasksIndex, function (err, results) {
    // Результат будет массивом
    console.log(results); // [231, 24]
});
async.series(taskNamed, function (err, results) {
    // Результат будет объектом 
    console.log(results); // {viewsNumber: 231, growFactor: 24}
});

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

Waterfall — этот метод работает словно цепочка, результаты одной задачи передаются в колбеке следующей задачи, таким образом можно:
async.waterfall([
    function(callback){
        callback(null, 'один', 'два');
  , }
    function(arg1, arg2, callback){
        // Тут arg1 равен "один"
        // , а arg2 равен "два"
        // что соответствует второму и третьему параметру текщего колбека
        // , а первый конечно же мы не забыли - это err но в этом случае
        // ошибок нет поэтому null
        callback(null, 'три');
  , }
    function(arg1, callback){
        // Здесь же arg1 будет равен уже "три"
        callback(null, 'Готово');
    }
], function (err, result) {
   // Сейчас результат будет равен 'Готово'    
});

Собственно это основные методы по контролю за выполнением колбеков, который упростят работу с ними, для получения более подробной информации советую посетить страничку модуля на Github.

воскресенье, 15 сентября 2013 г.

Nodejs. Тотальная установка на Windows 8 с поддержкой npm.

Итак собственно как же это дело провернуть, и вообще возможно ли такое в "недружелюбной" к ноде среде Windows? Возможно! Надо ли? А вот это уже решать Вам.
Итак что же мы будем ставить на машину под управлением операционной системы Windows 8
  1. Node.js
  2. Npm
  3. Redis
  4. MongoDB
Вот такой вполне обычный набор инструментов для NodeJS разработчика. Скажу честно это же поставить на, допустим, ту же Ubuntu вообще не составляет никакого труда. Чего увы не скажешь про Windows. Кто сталкивался с этой проблемой думаю меня поймут. Более того толкового мануальчика в рунете я не нашел, поэтому с успехом настроив себе рабочую среду для NodeJS спешу поделиться инструкциями по установке NodeJS с рабочим NPM (это даже важней чем сама нода) под Windows 8.
Итак приступим. В первую очередь качаем саму ноду устанавливаем, почему именно инсталятор, ну если просто бинарник качать то потом отдельно если я не ошибаюсь вам надо будет качать и npm и прописывать его вместе с нодой в системные пути, а так раз поставил... и все готово.
Собственно нода уже готова для работы. Но нода в "сыром" виде сейчас мало кого устроит. Многие уже сработались с определенным набором модулей. Например, для меня одни из самых основных модулей это:
  1. Expressjs
  2. Mongoose
  3. Mongodb
  4. Async
  5. Request
и многие другие.

Во многих проектах они прописаны в соответствующем файле, но увы если я выполню на этом этапе команду npm install в каталоге с проектом, но с большой долей вероятности многие нативные модули (а если точнее, то модули которые используют для сборки нативный модуль node-gyp) не скомпилируются, собственно все финиш. Нода как бы есть, а по факту ноды-то и нет. Для дальнейших действий обязательно убедитесь в том, что у вас в системе не установлены Visual C++ Redistributable это может повредить дальнейшей работе. Если у вас они установлены: удалите их. Вы возможно нуждались в их установке при настройке PHP+xdebug, увы как поведет себя эта связка после настройки ноды, я не знаю, не проверял.
Теперь надо установить вот эти вещи в том порядке, в котором я их приведу ниже, и очень важно! Не пытайтесь экспериментировать с версиями если вам надо ноду настроить как можно скорее, иначе рискуете увязнуть... и увязнуть надолго.
  1. Visual Studio 2010
  2. Windows SDK 7.1
  3. Visual Studio 2010 SP1
  4. Visual C++ 2010 SP1 Compiler Update for the Windows SDK 7.1
После всего этого программного пакета стоит еще до-уставновить немаловажную штуковину и это Python 2.7 он также необходим для корректной работы node-gyp.

Все! После проделанной работы переходим в корневой каталог вашего приложения и пробуем запустить npm install, должно все пройти гладко. После чего запускаем свое любимое приложения на node.js под Windows 8 x64 (собственно я думаю и под Win 7 тоже пойдет на ура)

И в догонку совсем забыл упомянуть про MongoDB и Redis. И если с монго проблем у вас быть не должно то вот редис, не совсем прост. Качаем с Git любым вашим любимым способом Redis в желаемое месторасположение. Затем в корне ищем по пути /bin/release/ бинарники, все вы их можете запускать и работать с редис под Win 8, но я рекомендую путь к бинарникам занести в системные пути (дописать в переменную PATH)

P.S.: Честно говоря, после Ubuntu настройка node.js под Windows 8 показалась мне жутким садизмом. Но было жалко выбрасывать на свалку впервые честно приобретенную Win 8, пускай и в комплекте с ноутом... а было бы круто если я бы я мог отдать ненужную систему и получить компенсацию, но это блин утопия :)

пятница, 12 июля 2013 г.

Ubuntu. Как узнать версию системы

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

lsb_release -a # Инфа об Убунте
uname -a # Все данные о системе
uname -m # Только разрядность x32 или x64

среда, 10 июля 2013 г.

MySQL. Инкремент при UPDATE

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

-- Определяем переменную
select @i := 0;
-- Используем ее в качестве инкремента и присваиваем значение нужному нам полю.
UPDATE `site_statistic` SET `ratePosition` = (select @i := @i + 1) ORDER BY myPoint DESC;

Пожалуй, все.

пятница, 15 февраля 2013 г.

Myseobot. Сервис по проверке технического состояния сайта.

Итак, если у вас есть сайт. И вы хотели бы его проверить или как то улучшить, в техническом плане. В плане того как его видят роботы, как они с ним работают. Насколько правильно составлен контент на вашем сайте. То добро пожаловать на мою собственную разработку myseobot.com это простой инструмент для проверки основных характеристик вашего сайта. Таких как Google PR, цитирование яндекса позиции занимаемые в поисковиках. Из технических проверок есть такие как проверка ссылок, проверка редиректов и точек входа на ваш сайт, корректность доменов и многое другое. Правда стоит оговориться. Сайт находиться в ранней альфе, возможны ошибки.

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

  • Семантический анализ
  • Анализ безопасности

Попутно будут исправляться ошибки и а также. Добавляться технические тесты.

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

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

вторник, 1 января 2013 г.

Мое мнение. Клавиатура Rapoo 9070.

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


Клавиатура действительно очень компактная, но не смотря на то что она имеет небольшие размеры. Клавиши довольно таки не малые. Клавиши имеют ход небольшой, но ощутимый. При нажатии где-то по середине хода кнопка имеет наибольшее сопротивление, продавив которое, кнопка стремительно проваливается и замыкает контакт. Шума от нажатия не много, в общем охарактеризую эту клавиатуру как тихую. Расположение кнопок относительно удобное, ноутбучное если можно так сказать. Не лишний, надо заметить и цифровой блок кнопок. Клавиатура успешно протестировалась на Win 7 и на Ubuntu 12.04. Работает отлично. Драйвера или спец, софт ставить вовсе не обязательно.
Я даже удивился немного когда увидел в других обзорах упоминание о том что мало софта для этой малышки. Если кто-то может объяснить чем это плохо, прошу в комменте отписать.

В работе показала себя хорошо. В особенности стоит отметить что клавиши курсора удивительно неплохо нащупываются. А вот чудо-клавиша "слеш", рядом с левым шифтом,  меня немного удивила, и именно из-за этой клавиши у меня на новой клавиатуре возникает большее количество опечаток. Это минус, такой противный и нехороший минус в адрес rapoo. Некоторые люди (видимо про-геймеры) пишут, что играть на ней не удобно. Странно, но мне удобно. Играл в шутер и реал-тайм стратегию. Что огорчило больше всего это то, что клавиатура бывает ни с того ни с сего теряет связь. Поиск дал смутный результат. Люди говорят что всему причина Wi-Fi приемник-передатчик по близости, увы у меня это так. И пока проверять не охота как оно будет без него. Не так уж часто она и "слепнет" :). Еще один недостаток, так это то, что нет индикатора CAPS LOCK'а, его действительно очень не хватает :(.
Питается девайс от двух элементов питания формата AAA (это те которые меньше "пальчиковых" батареек, если кто до сих пор не знает), у меня сейчас обычные батарейки, в дальнейшем думаю прикупить аккумуляторы.







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

воскресенье, 25 ноября 2012 г.

Phantomjs. Кратко о webkit консольном браузере.

Отличный браузер, который дает нам дополнительные возможности в программной навигации по вебу. А также позволяет реализовать unit-тестирование javaScript, делать скриншоты страниц и другое. Это браузер позволяет нам работать с DOM так же буд-то мы находимся в самом обычном браузере с GUI. Краткая информация:
У меня лично были некоторые трудности с установкой из исходников. Ах, да совсем забыл Ubuntu :). Значит были сложности, т.к. требуется qt и еще ряд зависимостей, если кто-то хочет попробовать собрать, то подробная инструкция по этому вопросу есть на сайте продукта. Также я поставил изначально из пакетов:
sudo aptitude install phantomjs
Но, как известно, стандартные пакеты славятся отсталостью версий. Как же быть если пакеты в репозиторые старые, а из сырцов поставить не вышло? На официальном сайте есть бинарники. Там вы найдете бинарники для популярных ОС.
Как пользоваться. Очень просто, куда вы распаковали скачанный архив, там находите папку bin а в ней phantomjs, его можно вынести в удобное для вас место. Итак приступим.
Первый самый простой скрипт (hello.js) для нашего phantomjs.
console.log('Hello Phantom!!!');
Для запуска выполним
phantomjs hello.js
Получим сообщение в консоль. Ну, это по-моему очевидно. Далее чуть поинтереснее. Пример получения скриншота посещаемой страницы:

var page = require('webpage').create();
page.open('http://google.com', function () {
    page.render('google.png');
    phantom.exit();
});
 
Тут мы сначала подключаем необходимый нам модуль webpage. А затем открывает необходимую нам страницу, после успешной загрузки которой мы вызовим колбэк функцию. В этой функции мы сохраняем (рендерим) скриншот страницы в файл google.png и закрываем phantomjs.

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

var page = require('webpage').create(),
    system = require('system'),
    t, address;

if (system.args.length === 1) {
    console.log('Usage: loadspeed.js ');
    phantom.exit();
}

t = Date.now();
address = system.args[1];
page.open(address, function (status) {
    if (status !== 'success') {
        console.log('FAIL to load the address');
    } else {
        t = Date.now() - t;
        console.log('Loading time ' + t + ' msec');
    }
    phantom.exit();
});

Запустив этот скрипт и передав в качестве параметра Web-адрес, мы получим ожидаемый результат, т. е. скорость загрузки страницы.

Гораздо больше примеров есть на официальном ресурсе, который указан вначале статьи. Штука удобная действительно. Я написал обертку на PHP для управления этим браузером, но она "дико" сырая, умеет выполнять только одно, вызывать обработчик phantomjs и делать скриншот в файл. Как будет что показать обязательно обновлю статью и укажу ссылочку на Git хаб.

Проброс портов в Windows

Ситуация проста. Имеем следующее. Виртуальную машину. Физическую машину на которой она крутиться. Если коротко то хост машина - Win7, гостевая - ubuntu-server 12.04., роутер. На роутере скорее всего для проброса портов будет пункт типа Virtual Servers. Там выбираем службу (или руками порты прописываем) IP машины на которую нам надо отправлять. Это сугубо индивидуально поэтому не могу ничего конкретно посоветовать. Смотрите документацию по своему роутеру. На тему "проброс портов".
Идем далее. На Убунте поднят апач, т.е. это 80 порт - это наша цель. Но роутер может обратиться только на наш физический IP адрес внутри локальной сети, на железную сетевую карту. Тут нам надо делать еще один проброс порта, того же 80го. Но только уже на нашем компьютере под управлением Win7 с железной карты, пускай у нее IP будет 192.168.1.101 на карту, которую добавит при установке, ваша виртуальная машина (у меня Virtual Box и карта которая соединяет виртуальные миры с физическими имеет адрес 192.168.56.1, ну шлюз, в смысле, соответственно машина с Апачем имеет IP равный 192.168.56.101). Итого, вкратце, надо пробросить 192.168.1.101:80 на 192.168.56.101:80 в операционной системе Windows 7 приступаем.
1. Запускаем консоль с правами администратора.
2. Запускаем netsh
и
netsh>interface
netsh interface>portproxy
netsh interface portproxy>add v4tov4 listenport=80 listenaddress=192.168.1.101 connectaddress=192.168.56.101 connectport=80
Проверяем все ли прошло гладко:
netsh interface portproxy>dump

#===========================
# Конфигурация портов прокси
#===========================
pushd interface portproxy

reset
add v4tov4 listenport=80 connectaddress=192.168.56.101 connectport=80


popd

# Конец конфигурации портов прокси
Да все нормально. Пробуем теперь обратиться локально по 192.168.1.101 и мы получим ответ от апача по адресу 192.168.56.101. Дальше пробуем уже по внешнему IP адресу, и вы должны получить тот же ответ что и от внутреннего адреса 192.168.56.101. Стоит уточнить, данный способ пробросит только TCP.

Если узрите неточности, прошу отметить в комментариях.


четверг, 30 августа 2012 г.

PHP. Работа с CSV файлами.

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

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

$options = array(
    'splitter' => ';', // Это разделитель "колонок" в CSV файле
    'wrapper' => '"', // А это то во что "завернуты" значения "колонок"
);
$csv = new Csv($options);
А вот так просто мы можем добавить строку в CSV файл, но данные сохранятся только после вызова метода Csv::save([file_name])
// Можно передать и в конструктор в виде параметра file => 'filename.csv'
$csv->file('./users.csv');
$csv->add(
    array ('id', 'user', 'name', 'email')
);
// Если как в этом примере мы указали имя файла то просто вызываем Csv::save если нет, то передаем в качестве параметра имя файла
$csv->save()

Если мы заранее указали имя файла с которым работаем, то и этот метод вызываем без параметров. Это загрузка CSV файла и его парсинг.

$csv->load();
или
$csv->load("./users.csv');

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

$csv->rows(); // Получаем все распарсенные строки из файла (в виде массива)
$csv->row(1); // Получи первую строку, причем если вы укажите в параметрах конструктора параметр columnNames, то это строка выведет данные а не названия столбцов
$csv->cell(10, 3); // Выведет данные из 10 строки 3 колонки
$csv->remove(3); // Удалит 3ю строку из файла
$csv->readOnly(true); // Пометить объект как "только чтение" и методы add и remove будут генерировать исключения
$data = $csv->columns() // Получить все колонки
$userNames = $csv->column('name'); // Получить колонку с именами (если конечно был задан map колонок)

// Весь поиск прекращает работу и возвращает строку как только будет найдена первая строка удовлетворяющая поиску
$csv->find('Vasya'); // Будет работать медленее всего, вернет первую строку в которой есть 'Vasya', регистр важен
$csv->find('Vasya', 2); // Будет работать быстрее чем предыдущий вариант, с таким же результатом, но не по всей таблице а только по 3й колонке
$csv->find('Vasya', 2, Csv::FIND_SENS_CASE); // Быстрый регистронезависимый поиск по 3й колонке
$csv->save(); // Сохраняем все изменения если конечно объект не помечен как "только чтение"
Замечу, что поиск работает очень быстро, разумеется для этого типа данных. Я потратил наверное больше всего времени на этот кусочек реализации. Думаю вы оцените, для сравнения, поиск по списку из 450 тыс. (колонок было 13), данные из середины, находились без указания колонки поиска за ~2с. а с указанием за ~0.5), конечно, эти данные абсолютно ни о чем не говорят, а просто приблизительно показывают, что поиск вполне можно использовать.
Благодаря этому классу, я смог быстро реализовать импорт/экспорт данных из CSV в Ms Excel XML и из CSV в MySQL, с минимальным набором логики, как вы заметили есть методы, которые позволяют манипулировать данными, думаю это очень важно.
И мне показалось, что не поделиться им с вами, будет не честно, зачем ему валяться без дела, пускай людям приносит радость и экономит время.

Скачать класс с Github
Можно забрать с composer

пятница, 10 августа 2012 г.

MySQL. Отключение логирования запросов без индексов.

MySQL при включенном slow log логирует и запросы которые не содержат в себе индексов. Порою возникает необходимость такую "фичу" отключить для этого необходимо найти конфигурационный файл mysql. В случае если это Debian то это будет /etc/mysql/my.cnf и добавить туда в секцию MySQL директиву log-queries-not-using-indexes. Что приведет к игнорированию запросов которые не используют индексы, только если, конечно, время выполнения такого запроса будет ниже чем установленный long-query-time

вторник, 3 июля 2012 г.

Разработка. Как передать HTTP_REFERER из flash.

Предыстория такова. Есть на некоем ресурсе флеш-виджет которые выполняет какие-то операции с пользовательским контентом. В моем конкретном случае, это фотографии. Задача стояла следующим образом. Необходимо собирать статистику показов с внешних ресурсов, т.е. сколько раз и где флешка засветилась на экранах пользователей. задача так же усложнялась и тем, что по сути показы должны были учитываться не самой флешки, а меняющихся в ней фотографий. Если же вам так же понадобится учитывать показ контента внутри флеш, то, увы, прийдется обратиться к флешеру, сваявшего этот виджет. Зачем я объясню позже.
Итак приступим. Все мы прекрасно знаем, что флешка передать реферера не может, вернее может, но этот реферер будет физическим адресом размещения самой флешки. Что не есть хорошо и нам абсолютно не надо. Так как же передать реферера? Очень просто, достаточно обвернуть выдачу флешки в php-скрипт. В котором мы будем выхватывать реферера учитывать показ. Если же у вас задача, так же как и у меня, "со звездочкой", то делаем нехитрый трюк с редиректом и добавлением параметра в запрос, таким вот образом. Получив реферер, в PHP скрипте, мы генерируем новый запрос к флешке и делаем по нему редирект. Флешка в своб очередь, получив этот параметр, добавляет его к каждому запросу (в моем случае фотографии) к нашему серверу, где этот запрос, обрабатывается скриптом, который учитывает всю необходимую нам информацию, включая реферера. Теперь чтоб совсем все стало ясно, приведу небольшой пример утопического кода (без проверок и пр. только логика, так что, пожалуйста не возмущайтесь понапрасну):

// Файл flashcatch.php
$file = './flash.swf';
$referer = $_SERVER['HTTP_REFERER'];
// Если не надо делать никаких более действий, то прямо здесь счетаем показ
// ...
// Устанавливаем тип содержимого
header('Content-Type: application/x-shockwave-flash');
// Читаем и отдаем флешку.
echo file_get_content($file);
exit();

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

// Файл flashcatch-trick.php
$file = './flash.swf';
$referer = $_SERVER['HTTP_REFERER'];
// Добавляем параметр к запросу на флешку например referer.
if (strpos($_SERVER['REQUEST_URI'], '?')) {
    $connector = '&';
} else {
    $connector = '?';
}
$newRequest = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] . $connector . 'referer=' . $referer;
// Если запрос является внешним и запрос не содержит в себе параметра referer то делаем редирект
if (isExternalRequest() && !$_REQUEST['referer']) {
    header ('Location: ' . $newRequest);
    exit();
}
// Устанавливаем тип содержимого
header('Content-Type: application/x-shockwave-flash');
// Читаем и отдаем флешку.
echo file_get_content($file);
exit();

И вот тут вспоминаем про флешера, во флешку передаем новый параметр в котором прописан реферер, в моем случае это параметр referer :). А флешер формируя запросы к к серверу для получения фотографий (аудио, видео), подставляет его и сервер при выдаче содержимого флешке учитывает реферера и показ, соответсвенно.

Функция isExternalRequest не приведена, ее не составит труда написать самому. Суть ее думаю ясна, вернет труЪ если это внешний запрос и фальс если свой же сервер запросил флешку.

среда, 27 июня 2012 г.

Google Maps. Курсоры рук для карты.

Если вдруг вам понадобяться такие вот руки как при перемещении курсора над картой или же при перемещении с нажатой кнопкой мыши то вот:
http://maps.google.com/mapfiles/openhand.cur
http://maps.google.com/mapfiles/closedhand.cur