Google+

Интерактивная консоль для CakePHP

Matt Curry смастерил плагин Interactive для плагина DebugKit.

Для чего он нужен?

В DebugKit добавляется новая панель — интерактивная консоль CakePHP. В ней можно:

выполнять простой пхп-код

10 % 4 //вернет 2
is_array(49) //вернет false

выполнять SQL

SELECT id FROM users WHERE email = 'test@test.com' //вернет id пользователя
UPDATE posts SET published = false; //вернет "No results found.", но обновление выполнит

Как объединить действия add и edit вместе

Контроллер

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

8 способов ускорить сайт на CakePHP

Введение

Всем известно, что CakePHP медленный. А вот что известно не всем — то что это запланировано изначально. У меня могут быть проблемы из-за того, что я делаю этот секрет достоянием общественности, но я осознанно иду на риск. У меня есть доказательства — список длиной в километр, в котором наглядно показано, что разработчики CakePHP активно скупают акции Dell, IBM, Cisco и других компаний, производящих серверное оборудование. Мы все слышали выражение «сервера стоят дешево, а программисты — дорого». Команда CakePHP нашла способ монетизировать его, выпустив фреймворк, который позволяет разрабатывать быстро, но работает медленно. Они хотят, чтобы вы покупали больше железа. Оригинально, да? Так что я здесь, чтобы положить конец всему этому. Каждый совет в этой статье — это минус одна золотая цепь на шее разработчиков CakePHP.

Использование String::insert для локализации в CakePHP

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

login_eng

и русский вариант

login_rus

Обратите внимание, что порядок следования ссылок «сброс пароля» и «создание аккаунта» изменен. Возникает вопрос, как сделать такую надпись с минимумом возни. И тут же возникает ответ — String::insert. Вот код (всей этой формы, хочу заметить, не только надписи)

if ($session->check(‘Message.auth’)) $session->flash(‘auth’);

$pass_opts = String::insert(
    __(‘You may :create or :recover’, true),
    array(
        ‘create’ => $html->link(__(‘create account’, true),
            array(‘plugin’=>‘users’, ‘controller’=>‘users’, ‘action’=>‘create’)),
        ‘recover’ => $html->link(__(‘reset password’, true),
            array(‘plugin’=>‘users’, ‘controller’=>‘users’, ‘action’=>‘reset’))
    )
);

echo $form->create(‘User’, array(‘action’ => ‘login’));
echo $form->input(‘email’);
echo $form->input(‘password’, array(‘after’ => $pass_opts));
echo $form->end(__(‘Login’, true));

Плюсы такого решения очевидны — очередное разделение кода и представления, формат вывода задается локализатором в его любимом poEdit (или чем он там пользуется). Не забудьте только ему сказать, чтобы не переводил слова с двоеточиями перед ними.

Щасливо.

Каждому контроллеру — свои хелперы

Хозяйке на заметку. Официальная документация CakePHP рекомендует добавлять хелперы в AppController вот так

//AppController
var $helpers = array(‘Html’, ‘Form’);

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

//DynapagesController
var $helpers = array(‘Html’, ‘Form’, ‘Session’);

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

//AppController
var $helpers = array(‘Html’, ‘Form’, ‘Javascript’);

//DynapagesController
function beforeFilter() {
    parent::beforeFilter();
    $this->helpers[] = ‘Session’;
}

Невелика хитрость, но все же. До скорых встреч.

Translate Behavior

Незаменимая вещь при разработке многоязычного сайта на CakePHP — translate behavior. Суть его работы в том, что создается виртуальное поле в модели и его содержимое отображается в зависимости от текущей локали.

Чтобы начать использовать сабж нужно создать таблицу интернационализации.

CREATE TABLE i18n (
    id int(10) NOT NULL auto_increment,
    locale varchar(6) NOT NULL,
    model varchar(255) NOT NULL,
    foreign_key int(10) NOT NULL,
    field varchar(255) NOT NULL,
    content mediumtext,
    PRIMARY KEY (id),
    INDEX locale (locale),
    INDEX model (model),
    INDEX row_id (foreign_key),
    INDEX field (field)
);

Дальше в модели (предположим что она называется Dynapage — динамическая страница и содержит поля id, tag) подключим behavior.

class Dynapage extends AppModel {
    var $name = ‘Dynapage’;

    var $actsAs = array(‘Translate’=>array(‘content’, ‘title’));
}

И вот собственно вся магия. Теперь поля content и title являются полноправными полями модели, Translate будет автоматически отслеживать их использование. При получении записи из базы данных вернутся все поля плюс локаль, то есть в нашем случае (id, tag, content, title, locale).

По умолчанию локаль берется из Configure.language, также ее можно установить вручную.

$this->Dynapage->locale = ‘rus’;

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

Вот такой вариант вернет запись вне зависимости от того, локализовано поле или нет (нелокализованные поля будут пустыми).

$this->Dynapage->locale = array(‘rus’);
$this->set(‘dynapage’, $this->Dynapage->read(null, $id));

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

CakePHP — уязвимость в компоненте Auth

14 января на хабре мне в приват написали об уязвимости в компоненте Auth фреймворка CakePHP и в качестве доказательства была приведена ссылка на скриншот дефейса thechaw.com, да и на самом сайте дефейс не был убран. В чем суть уязвимости, мне сообщить отказались, сославшись на то, что подробные инструкции переданы разработчикам. И действительно за предыдущий день есть changeset со скупым описанием «updating auth component and test with additional checks for missing data». И уже 16 числа выходит релиз 1.2.1, на который настоятельно рекомендуют обновится.

И в самом деле уязвимость довольно серьёзная. Приложив минимум усилий, можно получить доступ в качестве любого пользователя системы…

  1. Нужно найти форму, через которую происходит логин
  2. Найти поле вида data[User][username]. Название может отличаться, но суть ясна — это логин пользователя
  3. Любым образом (хоть сохранить страницу, хоть через firebug) изменить имя этого поля на что-то вроде data[User][usernage]. Конкретное значение не важно, главное чтобы логин не попал на сервер
  4. В поле data[User][password] ввести id пользователя под которым вы хотите залогиниться.
  5. Вы внутри

Как с этим бороться?

  • обновиться на версию 1.2.1. и следить за обновлениями регулярно
  • не забывать использовать Auth вместе с компонентом Security. Он добавляет в формы подпись и описанный метод изменения полей уже не прокатит.

Успехов!

Named Scope для CakePHP

В Ruby on Rails есть такая полезная вещь, как named scope, которая предоставляет элегантный и удобный способ поиска данных в модели. Для наглядности пример:

class User {:active => true}
  named_scope :inactive, :conditions => {:active => false}
end

# Использование
User.active # то же самое, что и User.find(:all, :conditions => {:active => true})
User.inactive # то же самое, что и User.find(:all, :conditions => {:active => false})

Теперь такую же штуку можно получить и в CakePHP. Для этого придется сходить вот сюда и скачать плагин NamedScope, положить его в папку с плагинами кэйка, а потом в модели написать:

var $actsAs = array(
    'NamedScope.NamedScope' => array(
        'active' => array(
            'conditions' => array(
                'User.is_active' => true
            )
        )
    )
);

а потом в контроллере можно писать так:

$active_users = $this->User->active('all');

или так:

$active_users = $this->User->find('active');

причем при каждом вызове можно добавлять все те же параметре, что и при обычном find.

$active_users = $this->User->find('active', array(
    'conditions' => array(
        'User.created' => '2008-01-01'
    ),
    'order' => 'User.name ASC'
));

параметры, переданные в find, будут иметь приоритет над определенными в named scope.

DebugKit для CakePHP

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

debug kit

Щелкая по разделам, можно получить доступ к отладочной информации:

  • Значения сессии
  • Параметры запроса
  • Список выполенных SQL-запросов
  • Время, затраченное на исполнение (с разбивкой по компонентам)
  • Сообщения, записанные в лог-файл
  • Использование памяти
  • Значения переменных, переданных во View

Чтобы увидеть все это у себя в приложении, достаточно плагин положить в папку plugins, а в AppController написать

public $components = array('DebugKit.toolbar');

Скачать исходный код можно отсюда. А можно с помощью Git

git clone git://github.com/cakephp/debug_kit.git