четверг, 28 марта 2013 г.

Yahoo Web Mail Service

На работе интернет только через прокси + закрыты все порты, кроме 80 и 433. А нужно было протестировать механизм регистрации на разрабатываемом сайте (с отправкой сообщения пользователю на мыло). Единственное что пришло в голову, это найти сервис электронной почты с открытым API и использовать его для отправки сообщений. Погуглив, нашел только на yahoo.com такой API. Вот тут его описание.
Для работы с Yahoo Web Mail Service, нужно:
  • Завести аккаунт на Yahoo.com.
  • Зайти на страницу управления вашими проектами и создаем новый. Проект - это сущность, которая является "учетной записью" вашего проекта на сервере Yahoo. Каждый проект имеет Consumer Key и Consumer Secret, по которым и осуществляется доступ к API.
  • Скачать здесь PHP-библиотеку для работы с Yahoo Web Mail Service и поместить её в директорию сайта.
  • Ниже приведен исходный код скрипта для работы с API:
    require_once 'ymclient.php';
    
    define('OA_CONSUMER_KEY', '****************************************************************************************************');
    define('OA_CONSUMER_SECRET', '****************************************');
    define('OA_CALLBACK_URL', 'http://localhost/');
    define('REQUEST_TOKEN_COOKIE_NAME', 'rt');
    define('ACCESS_TOKEN_COOKIE_NAME', 'at');
    
    $ymc = new YMClientRequest(OA_CONSUMER_KEY, OA_CONSUMER_SECRET,
     OA_CALLBACK_URL, '192.168.60.3:3128');
    
    header("Content-type: text/plain\r\n\r\n");
    message = new stdclass();
    $msg->message->subject = 'Test from Yahoo!';
    $msg->message->from = new stdclass();
    $msg->message->from->email = '*******@yahoo.com';
    $msg->message->to = new stdclass();
    $msg->message->to->email = '******@gmail.com';
    $msg->message->simplebody = new stdclass();
    $msg->message->simplebody->text = 'Hello, World!';
    if ($ymc->SendMessage($msg)===false)
     echo 'error';
    else
     echo 'ok';
    
    class YMClientRequest {
        function __construct($oaConsumerKey, $oaConsumerSecret, $callbackURL,
          $proxy=null) {
            $this->oaConsumerKey = $oaConsumerKey;
            $this->oaConsumerSecret = $oaConsumerSecret;
            $this->callbackURL = $callbackURL;
            $this->ymc = new YMClient($oaConsumerKey, $oaConsumerSecret, $proxy);
        }
        function __call($method, $arguments) {
            $tok = $this->__get_access_token();            
            $result = $this->ymc->$method($arguments, $tok);
            $newtok = $this->ymc->oauth_get_refreshed_token();
            if($newtok) {
                setcookie(ACCESS_TOKEN_COOKIE_NAME, 
                    YMClient::oauth_token_to_query_string($newtok));
            }
            return $result;
        }
        private function __get_access_token() {
            // Access token exists in a cookie
            if(isset($_COOKIE[ACCESS_TOKEN_COOKIE_NAME])
                && $_COOKIE[ACCESS_TOKEN_COOKIE_NAME]) {
                parse_str($_COOKIE[ACCESS_TOKEN_COOKIE_NAME], $tok);                
                return $tok;
            }
            // Handling a redirect back from login
            else if(isset($_COOKIE[REQUEST_TOKEN_COOKIE_NAME])
                && $_COOKIE[REQUEST_TOKEN_COOKIE_NAME]
                && isset($_REQUEST['oauth_verifier'])
                && $_REQUEST['oauth_verifier'] 
                && isset($_REQUEST['oauth_token'])
                && $_REQUEST['oauth_token']) {
    
                $tok = YMClient::oauth_token_from_query_string(
                    $_COOKIE[REQUEST_TOKEN_COOKIE_NAME]);
    
                if($tok['oauth_token'] != $_REQUEST['oauth_token'])
                    throw new Exception("Cookie and URL disagree "
                        ."about request token value");
    
                $tok['oauth_verifier'] = $_REQUEST['oauth_verifier'];                            
                $newtok = $this->ymc->oauth_get_access_token($tok);
    
                setcookie(REQUEST_TOKEN_COOKIE_NAME, "", time()-3600);
                setcookie(ACCESS_TOKEN_COOKIE_NAME,
                    YMClient::oauth_token_to_query_string($newtok));
                return $newtok;
            }
            else {
                list ($tok, $url) = $this->ymc->oauth_get_request_token(
                    $this->callbackURL);
                setcookie(REQUEST_TOKEN_COOKIE_NAME,
                    YMClient::oauth_token_to_query_string($tok));
                header("Location: $url");
            }
        }
    }
    
    В приведенном выше фрагменте используется прокси для подключению с API. Изначально библиотека этого не предусматривала, поэтому её пришлось несколько модифицировать. Исходный код модифицированной версии можно скачать здесь. Этот фрагмент отправляет электронное сообщение, что и требовалось.
Интересные факты(:
  • Аутентификация осуществляется через OAuth.

среда, 27 марта 2013 г.

Настройка NTP-сервера на Windows

Для того чтобы настроить NTP-сервер, необходимо в редакторе реестра зайти в каталог:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time.

В нем:
  • В подкаталоге Config, установить:
    • AnnounceFlags = 0x05
    • MaxNegPhaseCorrection = 0x2a300
    • MaxPosPhaseCorrection = 0x2a300
  • В подкаталоге Parameters, установить:
    • NtpServer = <адрес_сервера_для_синхронизации>,0x1
    • Type = NTP
  • В подкаталоге TimeProviders/NtpClient, установить:
    • Enabled = 1
  • В подкаталоге TimeProviders/NtpServer, установить:
    • Enabled = 1
    • AllowNonstandardModeCombinations = 1
    • InputProvider = 0
  • Перезапустить службу времени Windows или вызвать команду
    w32tm /update /config.
  • Всё.

суббота, 16 марта 2013 г.

Yii + PHPUnit + PhpStorm

В иерархии папок web-приложения Yii есть папка webroot/protected/tests/unit для создания unit-тестов.
Для того чтобы тесты работали по мимо PHPUnit должен быть установлен PHPUnit_Selenium и быть запущен Selenium Server.
Как установить PHPUnit и PHPUnit_Selenium написано в предыдущем посте.
Для настройки проекта для тестирования в PhpStorm, нужно создать PHPUnit конфигурацию, в которой:
  • DirectoryC:\www\casade\casade2\protected\tests\unit.
  • Поставить галочку Use alternative configuration file и выбрать в качестве конфигурационного файла  webroot/protected/tests/phpunit.xml.

пятница, 15 марта 2013 г.

Установка и настройка PHPUnit. Настройка PhpStorm

Установка PHPUnit

Установить PHPUnit можно через PEAR командой:
pear channel-discover pear.phpunit.de
pear install --alldeps phpunit/PHPUnit
Так же может потребоваться установка PHPUnit_Selenium. Но перед этим нужно добавить канал pear.symfony.com, т. к. PHPUnit_Selenium использует Symfony2 Yaml Component. Добавляется канал командой:
pear channel-discover pear.symfony.com
После этого можно устанавливать PHPUnit_Selenium:
pear install --alldeps phpunit/PHPUnit_Selenium

Настройка PhpStorm

PHPUnit в PhpStorm не требует каких-либо дополнительных настроек, главное чтобы в настройках Settings->PHP->Include path был путь к директории PEAR.

Установка и настройка PEAR

  1. Скачать PEAR http://pear.php.net/go-pear.phar.
  2. Скопировать его в отдельную папку, например c:\utils\pear.
  3. Выполнить команду php go-pear.phar.
  4. Во время установки PEAR спросит где Вы хотите сохранить конфигурационные файлы: system - в C:\Windows, local - в папке PEAR'а.
  5. Так же он спросит место расположения PHP, т. к. дописывает свой путь в include_path. Пусть к PEAR можно дописать в php.ini и после установки:
    ;***** Added by go-pear
    include_path=".;C:\utils\pear\pear"
    ;*****
  6. Послу установки можно добавить нужные каналы:
    pear channel-discover pear.phpunit.de
    pear channel-discover pear.symfony.com
    
  7. После этого можно устанавливать пакеты командой:
    pear install --alldeps phpunit/PHPUnit
    

О том как настраивать PEAR с помощью переменных окружения написано тут.

четверг, 14 марта 2013 г.

Настройка PEAR

Возникли сложности с настройкой параметров PEAR, посмотреть их можно вызвав команду:

pear config-show

Настройки можно задать через переменные окружения:

PHP_PEAR_MASTER_SERVER - master_server
PHP_PEAR_HTTP_PROXY    - http_proxy
PHP_PEAR_INSTALL_DIR   - php_dir
PHP_PEAR_EXTENSION_DIR - ext_dir
PHP_PEAR_DOC_DIR       - doc_dir
PHP_PEAR_BIN_DIR       - bin_dir
PHP_PEAR_DATA_DIR      - data_dir
PHP_PEAR_CFG_DIR       - cfg_dir
PHP_PEAR_WWW_DIR       - www_dir
PHP_PEAR_TEST_DIR      - test_dir
PHP_PEAR_TEMP_DIR      - temp_dir
PHP_PEAR_CACHE_DIR     - cache_dir
PHP_PEAR_DOWNLOAD_DIR  - download_dir
PHP_PEAR_PHP_BIN       - php_bin
PHP_PEAR_SYSCONF_DIR   - папка где находятся pear.ini и pearsys.ini.

Задавая эти параметры можно вообще не пользоваться командой pear config-set.

среда, 13 марта 2013 г.

Настройка PhpStorm для работы с XDebug

Вот фрагмент конфигурации XDebug из php.ini:
zend_extension = "C:/utils/wamp/bin/php/php5.4.7/ext/php_xdebug-2.2.1-5.4-vc9.dll"

[xdebug]
xdebug.remote_enable = on
xdebug.profiler_enable = on
xdebug.profiler_enable_trigger = off
xdebug.profiler_output_name = cachegrind.out.%t.%p
xdebug.profiler_output_dir = "c:/utils/wamp/tmp"

Для того чтобы XDebug заработал с PhpStorm нужно:
  • создать Run/Debug конфигурацию PHP Remote Debug;
  • в разделе Configuration для свойства Servers выбрать нужный сервер или создать новый;
  • для свойства Ide key ввести PHPSTORM;
  • нажать OK.
Далее выбрать созданную конфигурацию в кобмобоксе Select Run/Debug Configuration и нажать на кнопку Start Listen PHP Debug Connections и на Debug.

В браузере  (Google Chrome) установить расширение XDebug helper, после чего в углу адресной строки появится значок расширения, если он зеленый, нажав на него, можно включить отладку.

Если Вам необходимо установить XDebug, то для начала нужно скачать его для нужной версии PHP отсюда. После этого скопировать бинарник в папку с другими модулями. В php.ini прописать настройки в точности как написано в начале статьи. ВАЖНО: путь к бинарнику указать ПОЛНОСТЬЮ.

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

Yii: Использование CClientScript

Класс-компонент CClientScript предназначен для подключения js-скриптов и css-стилей.
По умолчанию доступ к нему осуществляется через Yii::app()->clientScript.
Компонент содержит свойство packages, с помощью которого можно формировать пакеты скриптов, через конфигурационный файл делается это так:
'components' => array( 
    'clientScript' => array(
        'packages' => array(
            'item' => array(
                'basePath'=>'application.assets'
                'js' => array('js/item.js'),
                'depends' => array('jquery'),
            ),
            'filter' => array(
                'basePath'=>'application.assets'
                'js' => array('js/filter.js'),
                'depends' => array('jquery'),
            ),
        ),
    ),
),
Тут создается 2 пакета - item и filter. В приведенном примере используется свойство 'basePath' равное 'application.assets'. Это значит что скрипт item.js хранится в папке protected/assets/js/. При обращении происходит публикация этих ресурсов и на странице мы увидим обращение к опубликованному скрипту /assets/d03789dg/js/item.js.
Вместо свойства 'basePath' можно использовать 'baseUrl', при этом конечный URL скрипта будет <baseUrl>/js/item.js.

Подключаются они во вьюшке так:
Yii::app()->clientScript->registerPackage('item');

Статья по теме, из нее и взяты фрагменты кода.

Yii: как работать с AssetManager

AssetManager предназначен для публикации файлов js, css, png и др. ресурсы в папке webroot/asserts/.

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

Публикация выполняется методом AssetManager::publish($path), где $path - путь к папке с ресурсами которые нужно опубликовать.

Часто для публикации ресурсов и последующего доступа к ним, в базовый класс контроллера добавляют свойство getAssetsUrl():

class Controller extends CController
{
   private $_assetsUrl;
   public function getAssetsUrl() {
       if ($this->_assetsUrl === null) {
           $this->_assetsUrl = Yii::app()->assetManager->
               publish(Yii::getPathOfAlias('application.assets'));
       }
       return $this->_assetsUrl;
   }
}
UPDATE Не знаю для чего создавать временную переменную, т.к. внутри метода publish тоже есть проверка о публикации.

И во вьющке используют это свойство так:
<link rel="stylesheet" type="text/css" href="<?=$this->assetsUrl?>/css/main.css" />

Вот статья по теме на хабре.