Ярлыки

.htaccess (4) тестирование (8) шаблоны проектирования (3) css (5) Debian (6) docker (2) Doctrine2 (6) Git (6) html (4) java (6) javascript (13) jquery (11) LFS (3) linux (23) mac os (4) mod_rewrite (2) MSSQL (4) MySQL (18) ORM Doctrine (17) patterns (3) PDO (3) perl (7) PHP (64) PHPUnit (8) Python (15) SEO (2) Silex (1) SimpleXML (1) SQL (14) ssh (4) Ubuntu (24) Yii1 (1) Zend Framework (19) ZendFramework2 (8)

четверг, 21 ноября 2013 г.

Zend Framework. Использование скрипта вида для отображения элемента формы на примере Captcha.

class My_Form extends Zend_Form 
{

...

$this->addElement('Captcha', 'cap', array(
    'label' => 'Введите код на картинке * :',
    'required' => true,
    'disableLoadDefaultDecorators' => true,
    'decorators' => array('Captcha', array('ViewScript', array(
       'viewScript' => 'captcha.phtml',
       'placement' => false,
    ))),
    'captcha' => array(
       'captcha' => 'image',
       'width' => 100,
       'height' => 50,
       'name' => 'foo',
       'wordLen' => 3,
       'font' =>  '/path/to/fonts/arial.ttf',
       'fontSize' => 18,
       'imgDir' => '/path/to/images/captcha',
       'imgUrl' => 'http://' . $_SERVER['HTTP_HOST'] . '/images/captcha/',
       'timeout' => 300,
       'lineNoiseLevel' => 0,
       'dotNoiseLevel' => 0,
       'messages' => array(
            'badCaptcha' => 'Вы ввели неверный код'
       ))
));
            

...
}
<div style="float: left;">
    <label><?= $this->element->getLabel() ?></label>
    <input id="captcha" type="text" name="cap[input]" />
    <? if ($this->element->hasErrors()): ?>
        <?= $this->formErrors($this->element->getMessages()) ?>
    <? endif; ?>
    <input type="hidden" 
              name="cap[id]"  
              value="<?= $this->element->getValue() ?>" />
</div>
<div style="float: left;">
<?= $this->element->getCaptcha()->render() ?></div>
<div class="clear"></div>

вторник, 15 октября 2013 г.

Zend Framework. Zend_Search_Lucene ошибка при оптимизации индекса.

PHP Fatal error:  Uncaught exception 'Zend_Search_Lucene_Exception' 
with message 'fopen(/../_6z7u.cfs):
failed to open stream: Too many open files' 
in /../library/Zend/Search/Lucene/Storage/File/Filesystem.php:67
в консоли выполняем
ulimit -n5000
Подробнее тут

четверг, 10 октября 2013 г.

Отличный абсолютно бесплатный хостинг без рекламы!


Hostinger.ru 

Рекомендую отличный совершенно бесплатный хостинг, абсолютно без рекламы. Платный хостинг тоже на уровне в том числе и VPS.
Поддержка полностью устраивает.
PHP 5.4 на шаред.

вторник, 17 сентября 2013 г.

ZendFramework2. Установка макета в модуле и контроллере.

В модуле
...

use Zend\ModuleManager\ModuleManager;

class MyModule implements AutoloaderProviderInterface
{
    public function init(ModuleManager $moduleManager)
    {
        $sharedEvents = $moduleManager->getEventManager()
                            ->getSharedManager();
        $sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
            // Событие сработает при вызове ActionController
            // в пространстве имен MyModule.
            $controller = $e->getTarget();
            $controller->layout('layout/index');
        }, 100);
    }
}

В контроллере

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $this->layout('layout/index');
        return array();
    }
}

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

ZendFramework2. Перевод сообщений валидатора на русский язык.

Для того чтобы валидаторы заговорили по-русски или на любом другом языке, а это сообщения об ошибках в формах и тд, делаем следующее:

namespace MyModule;

use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\Validator\AbstractValidator;

class Module implements AutoloaderProviderInterface
{
   ...

   $translator = $e->getApplication()->getServiceManager()
                     ->get('translator');
   $translator->addTranslationFile(
       'phpArray',
'./vendor/zendframework/zendframework/resources/languages/ru/Zend_Validate.php',
       'default',
       'ru_RU'
   );
   AbstractValidator::setDefaultTranslator($translator);

   ...
}

А так же можем вообще добавить свой файл переводов. Мне, например, он понадобился для локализации сообщений модуля ZfcUser, которые просто заданы как свойства контроллера.
   ...

   $translator->addTranslationFile(
       'phpArray',
       './module/MyModule/language/ru.php',
       'default',
       'ru_RU'
   );

   ...

Ну и сам файл переводов создаем module/MyModule/language/ru.php

return array(
    'Authentication failed. Please try again.' =>
        'Неверный пароль или логин. Попробуйте еще раз.'
);

четверг, 12 сентября 2013 г.

ZendFramework2. Совместная работа ScnSocialAuth и CdliTwoStageSignup.

Два очень полезных модуля для Zend Framework 2.
Которые не хотят работать вместе из коробки.
Все действия будут в контексте модуля Application из Skeleton.
В контроллере User модуля ScnSocialAuth, в действии register напрямую вызывается действие register модуля ZfcUser.
Как результат мы видим обычную форму регистрации со всеми полями,
несмотря на то, что все плагины подключены в нужной последовательности.
Все что мне нужно, чтобы вместо него вызывалось действие email-verification модуля CdliTwoStageSignup, которое отвечает за отрисовку формы первого этапа регистрации с проверкой почты.

1. Создаем свой контроллер, расширящий
 \ScnSocialAuth\Controller\UserController

Application/src/Application/Controller/SocialAuthController.php
 
namespace Application\Controller;

use Zend\View\Model\ViewModel;

class SocialAuthController 
    extends \ScnSocialAuth\Controller\UserController
{
    public function registerAction()
    {
        // вызываем контроллер CdliTwoStageSignup
        $zfcUserRegister = $this->forward()
            ->dispatch('cdlitwostagesignup_ev_controller',
               array('action' => 'email-verification'));
        /*if (!$zfcUserRegister instanceof ModelInterface) {
            return $zfcUserRegister;
        }*/
        $viewModel = new ViewModel();
        $viewModel->addChild($zfcUserRegister, 'zfcUserLogin');
        $viewModel->setVariable('options', $this->getOptions());

        $redirect = false;
        if ($this->getServiceLocator()->get('zfcuser_module_options')
                ->getUseRedirectParameterIfPresent() 
                    && $this->getRequest()->getQuery()->get('redirect')) {
            $redirect = $this->getRequest()->getQuery()->get('redirect');
        }
        $viewModel->setVariable('redirect', $redirect);
        // подключаем шаблон оригинального модуля
        $viewModel->setTemplate('scn-social-auth/user/register');

        return $viewModel;
    }

}

2. Создаем фабрику контроллера для первоначальной инициализации
по аналогии с фабрикой из ScnSocialAuth

Application/src/Application/Service/SocialAuthControllerFactory.php
 
namespace Application\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class SocialAuthControllerFactory implements FactoryInterface
{
    public function createService(
        ServiceLocatorInterface $controllerManager)
    {
        $mapper = $controllerManager->getServiceLocator()
            ->get('ScnSocialAuth-UserProviderMapper');
        $hybridAuth = $controllerManager->getServiceLocator()
            ->get('HybridAuth');
        $moduleOptions = $controllerManager->getServiceLocator()
            ->get('ScnSocialAuth-ModuleOptions');

        $controller = new \Application\Controller\SocialAuthController();
        $controller->setMapper($mapper);
        $controller->setHybridAuth($hybridAuth);
        $controller->setOptions($moduleOptions);
        return $controller;
    }
}

3. Настройки в конфигурации нашего модуля

Application/config/module.config.php
 
...

'router' => array(
        'routes' => array(

            ...

            // создаем роут на наш контроллер
            'social-auth' => array(
                'type' => 'Literal',
                'priority' => 2000,
                'options' => array(
                    'route' => '/user',
                    'defaults' => array(
                        'controller' => 'zfcuser',
                        'action'     => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'register' => array(
                        'type' => 'Literal',
                        'options' => array(
                            'route' => '/register',
                            'defaults' => array(
                                'controller' =>
                                    'Application\Controller\SocialAuth',
                                'action'     => 'register',
                            ),
                        ),
                    ),

                ),
            ),
        ),
    ),

'controllers' => array(
        
        ...

        // регистрируем фабрику контроллера
        'factories' => array(
            'Application\Controller\SocialAuth' =>
                'Application\Service\UserControllerFactory',
        ),
    ), 

пятница, 6 сентября 2013 г.

MySQL. Добавление внешнего ключа.

В дополнение к заметкам об удалении внешнего ключа mysql и возможных ошибках при удалении внешнего ключа innodb
CREATE TABLE `category` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `parent_id` int(11) DEFAULT NULL,
    `slug` varchar(255) NOT NULL,
    `title` varchar(255) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `slug` (`slug`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

ALTER TABLE category 
ADD CONSTRAINT id_parent_id FOREIGN KEY (parent_id)
      REFERENCES category (id)
      ON UPDATE CASCADE ON DELETE CASCADE

понедельник, 19 августа 2013 г.

ZendFramework2. Собственный модуль авторизации и ACL, объединяющий ZfcUser, BjuAuthorize, Doctrine2.

Я опущу установку приложения Zend Framework 2 и установку модулей ZfcUser, BjuAuthorize, Doctrine2. Перейдем сразу к созданию собственного модуля.

Создаем структуру модуля

/module/MyUser
    /config
        doctrineconnection.local.php.dist
        module.config.php
    /src
        /MyUser
            /Entity
                Role.php
                User.php
    Module.php
Добавляем модуль в /config/application.config.php.

doctrineconnection.local.php.dist настройки подключения Doctrine, нужен только если они не указаны где-то за пределами модуля. Как правило настройки уже присутствуют в каталоге /config/autoload приложения.

return array(
    'doctrine' => array(
        'connection' => array(
            'orm_default' => array(
                'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
                'params'      => array(
                    'host'     => '127.0.0.1',
                    'port'     => '3306',
                    'user'     => 'dbuser',
                    'password' => '',
                    'dbname'   => 'mydb'
                )
            )
        )
    )
);
MyUser/Module.php
class Module {
    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }

    public function getAutoloaderConfig()
    {
        return array(
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }
}
MyUser/config/module.config.php
return array(
    'doctrine' => array(
        'driver' => array(
            // перектрываем настройки zfc-user-doctrine-orm
            // используем AnnotationDriver
            // и указываем путь к каталогу с классами модели
            'zfcuser_entity' => array(
                'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
                'paths' => __DIR__ . '/../src/MyUser/Entity',
            ),

            'orm_default' => array(
                'drivers' => array(
                    'MyUser\Entity' => 'zfcuser_entity',
                ),
            ),
        ),
    ),

    'zfcuser' => array(
        // указываем, что ZfcUser должен использовать наш класс пользователя
        'user_entity_class'       => 'MyUser\Entity\User',
        // указываем ZfcUserDoctrineORM игнорировать сущности по-умолчанию
        'enable_default_entities' => false,
    ),

    'bjyauthorize' => array(
        // Using the authentication identity provider, 
        // which basically reads the roles from the auth service's identity
        'identity_provider' => 
            'BjyAuthorize\Provider\Identity\AuthenticationIdentityProvider',

        'role_providers' => array(
            // используем репозиторий объектов
            // для загрузки ролей в ACL
            'BjyAuthorize\Provider\Role\ObjectRepositoryProvider' => array(
                'object_manager'    => 'doctrine.entity_manager.orm_default',
                // указываем наш класс для ролей
                'role_entity_class' => 'MyUser\Entity\Role', 
            ),
        ),
    ),
);

Создаем классы User и Role

Проще всего скопировать шаблоны классов из модуля bjy-authorize
 /vendor/bjyoungblood/bjy-authorize/data/Role.php.dist
 в
 /module/MyUser/src/MyUser/Entity/Role.php
и
 /vendor/bjyoungblood/bjy-authorize/data/User.php.dist
в /module/MyUser/src/MyUser/Entity/User.php
в этим классах везде меняем пространство имен на наше
Mynamespace на MyUser\Entity

Проверяем

> vendor/bin/doctrine-module orm:validate-schema
[Mapping]  OK - ...
[Database] FAIL - .....
Схема модели работает, осталось обновить базу данных (точнее создать таблицы)
> vendor/bin/doctrine-module orm:schema-tool:update --force
Updateing database schema...
Database schema updated successfully! "6" queries were executed
Теперь в базе данных имеем три таблицы
    role
    users
    users_roles
Добавляем роли в таблицу
INSERT INTO `role` 
    (`id`, `parent_id`, `roleId`) 
VALUES
    (1, NULL, 'guest'),
    (2, 1, 'user'),
    (3, 2, 'moderator'), 
    (4, 3, 'administrator');

ZendFramework2. Использование собственных модулей на примере расширения возможностей ZfcUser.

Изменение маршрутов

По умолчанию модуль использует маршрут user. Мы хотим поменять на account.
Важно!!! Наш модуль регистрируется после стандартного модуля.
В таком случае настройки подхватываются последовательно и мы можем перекрыть стандартные настройки модуля ZfcUser в файле настроек нашего модуля.
return array(

    ...

    // Перекрываем маршрут zfcuser
    'router' => array(
        'routes' => array(
            'zfcuser' => array(
                'options' => array(
                    'route' => '/account',
                ),
            ),
        ),
    ),
);

Изменение скриптов вида

Каталог скриптов вида стандартного модуля называется 'zfc-user'.
Например, шаблон с формой регистрации будет 'view/zfc-user/user/register.phtml'.
Все что нам нужно, это просто создать альтернативный шаблон в нашем модуле с аналогичным путем и убедится, что шаблоны нашего модуля подхватываются уровнем вида приложения.
Для этого в настройках модуля должно быть следующее:
return array(
    ...

    // Указываем менеджеру вида путь к шаблонам в нашем модуле
    'view_manager' => array(
        'template_path_stack' => array(
            'application' => __DIR__ . '/../view',
        ),
    ),
);

Изменение формы

ZfcUser генерирует событие после выполнения метода init, то есть после создания формы со всеми элементами. Событие так и называется 'init' а идентификатор 'ZfcUser\Form\Register'.Таким образом, если мы хотим, например, добавить чекбокс в форму, то у нас есть такая возможность. Мы должны использовать слушатель события 'init'. Нам нужно создать слушатель в классе нашего модуля. Класс модуля должен реализовавать интерфейс 'Zend\ModuleManager\Feature\BootstrapListenerInterface'
в котором есть метод onBootstrap.
...
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
...

class Module implements BootstrapListenerInterface {

...

    public function onBootstrap(Event $e){
        $app = $e->getParam('application');
        // $em объект Zend\EventManager\SharedEventManager
        $em  = $app->getEventManager()->getSharedManager();

        $em->attach('ZfcUser\Form\Register', 'init', function($e) {
            // $form объект ZfcUser\Form\Register
            $form = $e->getTarget();

            $form->add(array(
                'name' => 'accept',
                'options' => array(
                     'label' => 'Accept Terms of Use',
                ),
                'attributes' => array(
                    'type' => 'checkbox'
                ),
            ));
        });
    }

...

}
Похожий вариант с ZfcUser\Form\RegisterFilter, котoрый тоже генерирует событие init:
public function onBootstrap(Event $e){
    $app = $e->getParam('application');
    // $em объект Zend\EventManager\SharedEventManager
    $em  = $app->getEventManager()->getSharedManager();

    $em->attach('ZfcUser\Form\Register', 'init', function($e) {
        // $form объект ZfcUser\Form\Register
        $form = $e->getTarget();

        $form->add(array(
            'name' => 'accept',
            'options' => array(
                'label' => 'Accept Terms of Use',
            ),
            'attributes' => array(
                'type' => 'checkbox'
            ),
        ));
    });
}
К сожалению, далеко не все модули используют EventManager для оповещения о событиях ;-(
В таком случае этот подход не будет работать.

суббота, 17 августа 2013 г.

Javascript. Один из вариантов наследования объектов.

function foo()
{
    this.name = "foo";
    this.testFoo = function () 
    {
        return "testFoo()";
    }
}

function bar()
{
    foo.call(this); // меняем контекст foo на bar
    this.getName = function () 
    {
        return this.name + "bar";
    }
    this.testBar = function ()
    {
        return "testBar()";
    }
    this.testFoo = this.testBar;
}

mybar = new bar();
alert(mybar.getName()); // foobar
alert(mybar.testFoo()); // testBar()

пятница, 16 августа 2013 г.

Git. Поврежденный репозиторий, fatal: loose object.

Виртуальная машина жестко повесила ubuntu. Помог только сброс питания. ;-( Как результат - повреждение репозитория Git. ;-((( В консоли выглядит следующим образом
user@user-laptop:~/www/project$ git status
error: object file .git/objects/41/42ee9d7ea7c1bceac107c406e865fac72411fd is empty
fatal: loose object 4142ee9d7ea7c1bceac107c406e865fac72411fd 
(stored in .git/objects/41/42ee9d7ea7c1bceac107c406e865fac72411fd) is corrupt
Хорошо, мастер-репозиторий есть на тестовом сервере и на продакшене. Архивируем локальный проект и клонируем мастер на локальную машину. Накатываем все, что указано в .gitignore на новое дерево проекта; ставим права на каталоги, если надо.

вторник, 18 июня 2013 г.

PHP. Падает apache.

Если по совершенно непонятной причине сервер не отдает страницу. А в логах apache наблюдается похожее:
[Tue Jun 18 19:49:13 2013] [notice] child pid 6141 exit signal Segmentation fault (11)
zend_mm_heap corrupted
[Tue Jun 18 19:57:50 2013] [notice] child pid 5585 exit signal Segmentation fault (11)
zend_mm_heap corrupted
[Tue Jun 18 20:00:32 2013] [notice] child pid 14010 exit signal Segmentation fault (11)

то помогает - увеличить значение output_buffering в php.ini Почему? Не разбирался ...

понедельник, 3 июня 2013 г.

Doctrine2. Кодировка текстовых полей при генерации таблиц.

Чтобы текстовые поля в таблице создавались в нужной кодировке надо указать опцию collate
/**
 * @Entity @Table(name="modifications", options={"collate"="utf8_general_ci"})
 */
class Modification 
{
    /** @Id @Column(type="integer") @GeneratedValue **/
    protected $id;
    
    /** @Column(type="string", length=255) **/
    protected $name;
}

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

Linux. SMPlayer тормозит fullhd видео?

Тормозит fullhd видео 1080p высокого качества и при этом процессор два ядра?
Выставляем многопоточное декодирование:




























Видео не реагирует на настройки эквалайзера (контраст, свет и тд.)?
Включаем эквалайзер в настройках:


понедельник, 22 апреля 2013 г.

суббота, 20 апреля 2013 г.

Linux. mkdir создание структуры каталогов в одну строку.

mkdir -pv application/module/Post/ \
        {config,src/Post/{Controller,Form,Model},view/post/post}
mkdir: created directory `application'
mkdir: created directory `application/module'
mkdir: created directory `application/module/Post'
mkdir: created directory `application/module/Post/config'
mkdir: created directory `application/module/Post/src'
mkdir: created directory `application/module/Post/src/Post'
mkdir: created directory `application/module/Post/src/Post/Controller'
mkdir: created directory `application/module/Post/src/Post/Form'
mkdir: created directory `application/module/Post/src/Post/Model'
mkdir: created directory `application/module/Post/view'
mkdir: created directory `application/module/Post/view/post'
mkdir: created directory `application/module/Post/view/post/post'

пятница, 19 апреля 2013 г.

Doctrine2. Генерация сущностей из YAML.

cli-config.php
...
$config = new \Doctrine\ORM\Configuration();
...
$driverImpl = 
    new \Doctrine\ORM\Mapping\Driver\YamlDriver(
        array(__DIR__ . "/yaml"));
$config->setMetadataDriverImpl($driverImpl);
Генерируем классы из схем в каталоге yaml и обновляем таблицы в базе данных.
Классы создаются в каталоге Entities (по умолчанию), поэтому скрипту передаем параметр ""
php doctrine.php orm:generate-entities --generate-annotations=1 ""
php doctrine.php orm:schema-tool:update --force

четверг, 18 апреля 2013 г.

Apache. Настройка SSL (HTTPS) в Ubuntu 12.04.

1. Включаем модуль Apache
sudo a2enmod ssl
sudo service apache2 restart
2. Создаем каталог для хранения ключей
sudo mkdir /etc/apache2/ssl 
3. Создаем сертификат
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ 
      -keyout /etc/apache2/ssl/apache.key \ 
      -out /etc/apache2/ssl/apache.crt
-days 365 // действителен 365 дней Отвечаем на вопросы диалога.
-----
Country Name (2 letter code) [AU]:UA
State or Province Name (full name) [Some-State]:Sevastopol
Locality Name (eg, city) []:Sevastopol
Organization Name (eg, company) [Internet Widgits Pty Ltd]:home
Organizational Unit Name (eg, section) []:home
Common Name (e.g. server FQDN or YOUR name) []:myname
Email Address []:myemail@email.com

4. Создаем для нового или копируем для существующего файл конфигурации виртуального хоста Далее на примере default
sudo nano /etc/apache2/sites-available/default
- меняем порт
        <VirtualHost *:443>
- добавляем строку ниже ServerAdmin 
        ServerName myhost:443 
- добавляем строки в файл конфигурации хоста 

        SSLEngine on 
        SSLCertificateFile /etc/apache2/ssl/apache.crt 
        SSLCertificateKeyFile /etc/apache2/ssl/apache.key 

5. Активируем виртуальный хост 
sudo a2ensite default
sudo service apache2 reload
Принудительное использование SSL (HTTPS) с помощью .htaccess Иногда необходимо принудительно заставить пользователя использовать шифрованное SSL (HTTPS) соединение. С помощью .htaccess это можно сделать так:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
Теперь, для папки и всех ее подпапок, в которой находится файл .htaccess с таким содержимым будет производиться автоматическая переадресация с использованием защищенного SSL (HTTPS) соединения.

пятница, 25 января 2013 г.

ASUS X501A 8Gb оперативной памяти

Сегодня воткнул в данный ноут планку 8Gb RAM. Правда пришлось для этого практически разобрать его. Не предназначен он для апгрейдов ;-) один слот всего, но радует, что память не напаяна, как в macbook air. На очереди установка SSD, диск менять несколько проще.
Так что, несмотря, на информацию на офф сайте ASUS, что потолок для этой модели 4Gb, апгрейд возможен.

четверг, 24 января 2013 г.

PHP. Сортировка массива по шаблону.

Хотим, чтобы строка zzzxxx была первой:
$arr = array("aaaxxx", "aaayyy", "bbbxxx", "bbbyyy", "zzzxxx");
usort($arr, function ($a) {
    return !preg_match("/zzz/", $a);
});
print_r($arr);

Array
(
    [0] => zzzxxx
    [1] => aaaxxx
    [2] => aaayyy
    [3] => bbbyyy
    [4] => bbbxxx
)