Pull to refresh

Система ловушек в phpBB3

Reading time11 min
Views2.6K

1. Введение


Что это?

Система ловушек позволяет разработчикам приложений и модов устанавливать ловушки в код phpBB или использовать их в своих собственных функциях.

Функции phpBB, с которыми можно использовать ловушки

В phpBB есть 4 функции, которые вы можете перехватить своими ловушками:

phpbb_user_session_handler() – вызывается внутри user::setup после корректной инициализации объектов session и user;
append_sid($url, $params = false, $is_amp = true, $session_id = false) — вызывается для формирования ссылок (добавления идентификатора сессии);
$template->display($handle, $include_once = true) – вызывается прямо перед выводом (еще не скомпилированного) шаблона;
exit_handler() – вызывается в самом конце выполнения кода phpBB3.

Пожалуйста обратите внимание: ловушка, использующая $template->display может принимать третий аргумент $template (ссылку на объект $template), который может использоваться вместо глобального.

Если вы интегрировали phpBB3 с вашим приложением, то возможно вы захотите использовать константы:

PHPBB_MSG_HANDLER (перезаписать message handler);
PHPBB_DB_NEW_LINK (перезаписать параметр new_link для sql_connect);
PHPBB_ROOT_PATH (перезаписать $phpbb_root_path);
PHPBB_ADMIN_PATH (перезаписать $phpbb_admin_path);
PHPBB_USE_BOARD_URL_PATH (использовать generate_board_url() для картинок вместо $phpbb_root_path).

Если константа PHPBB_USE_BOARD_URL_PATH установлена в true, то phpBB использует generate_board_url() (которая возвращает ссылку на форум с включенным путем к скрипту) для всех загружаемых картинок. Эта константа находится в файлах:

/includes/session.php — user::img()
/includes/functions_content.php — smiley_text()

Она также изменит пути в переменных шаблонов:
{T_THEME_PATH} — styles/xxx/theme
{T_TEMPLATE_PATH} — styles/xxx/template
{T_SUPER_TEMPLATE_PATH} — styles/xxx/template
{T_IMAGESET_PATH} — styles/xxx/imageset
{T_IMAGESET_LANG_PATH} — styles/xxx/imageset/yy
{T_IMAGES_PATH} — images/
{T_SMILIES_PATH} — $config['smilies_path']/
{T_AVATAR_PATH} — $config['avatar_path']/
{T_AVATAR_GALLERY_PATH} — $config['avatar_gallery_path']/
{T_ICONS_PATH} — $config['icons_path']/
{T_RANKS_PATH} — $config['ranks_path']/
{T_UPLOAD_PATH} — $config['upload_path']/
{T_STYLESHEET_LINK} — styles/xxx/theme/stylesheet.css (или ссылка на style.php, если css формируется динамически)
Новая шаблонная переменная {BOARD_URL} состоит из board url + script path.

2. Разрешаем использовать ловушки в функциях и методах классов

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

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

  1. function my_own_function($my_first_parameter, $my_second_parameter)
  2. {
  3.     global $phpbb_hook;
  4.  
  5.     if ($phpbb_hook->call_hook(__FUNCTION__, $my_first_parameter, $my_second_parameter))
  6.     {
  7.         if ($phpbb_hook->hook_return(__FUNCTION__))
  8.         {
  9.             return $phpbb_hook->hook_return_result(__FUNCTION__);
  10.         }
  11.     }
  12.  
  13.     [ЗДЕСЬ ВАШ КОД]
  14. }


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

А этот пример показывает, как вы могли бы заставить метод класса перехватывать ловушки…
  1. class my_hookable_object
  2. {
  3.     function hook_me($my_first_parameter, $my_second_parameter)
  4.     {
  5.         global $phpbb_hook;
  6.  
  7.         if ($phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $my_first_parameter, $my_second_parameter))
  8.         {
  9.             if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
  10.             {
  11.                 return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
  12.             }
  13.         }
  14.  
  15.         [ЗДЕСЬ ВАШ КОД]
  16.     }
  17. }


Здесь единственное отличие в том, как вы определяете первый параметр. Для функции это только константа __FUNCTION__, а для метода – массив array(__CLASS__, __FUNCTION__). В PHP4 константа __CLASS__ всегда возвращает название класса в нижнем регистре.

Теперь, в phpBB появились предопределенные функции, которые могут перехватывать ловушки, но как их сделать доступными (и следовательно разрешить другим перехватывать их)? Для этого есть метод add_hook():
  1. // добавление вашей собственной функции, которая может
  2. // ловить ловушки
  3. $phpbb_hook->add_hook('my_own_function');
  4.  
  5. // добавление вашего собственного метода, который может
  6. // ловить ловушки
  7. $phpbb_hook->add_hook(array('my_hookable_object', 'hook_me'));

Вы также сможете удалить возможность перехватывания ловушек функцией/методом вызовом $phpbb_hook->remove_hook() с теми же параметрами, что и add_hook(). Это пригодится, если вы захотите, чтобы некоторые ловушки не вызывались.

3. Регистрация ловушек

Теперь перейдем к определению ваших функций, которые должны будут вызываться. Для этого мы возьмем функцию append_sid() в качестве примера (эта функция может быть использована ловушками по умолчанию) и создадим два класса и функцию:
  1. class my_append_sid_class{
  2.  
  3.     // наши функции
  4.     function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false){
  5.  
  6.            // получить возможные результаты выполнения предыдущей ловушки
  7.            $result = $hook->previous_hook_result('append_sid');
  8.  
  9.            return $result['result'] . '<br /> а я был вторым.';
  10.     }
  11. }
  12.  
  13. // еще один класс
  14. class my_second_append_sid_class{
  15.  
  16.     function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false){
  17.    
  18.         // получить возможные  результаты выполнения предыдущей ловушки
  19.         $result = $hook->previous_hook_result('append_sid');
  20.  
  21.         echo $result['result'] . '<br />а я третим.';
  22.     }
  23. }
  24.  
  25. // обычная функция
  26. function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false){
  27.  
  28.     // получить возможные результаты выполнения предыдущей ловушки
  29.     $result = $hook->previous_hook_result('append_sid');
  30.  
  31.     return 'Я был вызван первым';
  32. }
  33.  
  34. // инициализация второго класса
  35. $my_second_append_sid_class = new my_second_append_sid_class();


Убедитесь, что вы добавляете те же самые параметры в вашу функцию, что определены для функции, перехватывающей ловушки с одним исключением: первый параметр всегда &$hook, ссылка на объект hook, с которым вы сможете работать.

Теперь мы зарегистрируем ловушки одной за другой с помощью метода $phpbb_hook->register():
  1. // Теперь мы зарегистрируем наши “заменители” функции append_sid по порядку...
  2. // Регистрируем функцию (вызывается первой)
  3. $phpbb_hook->register('append_sid', 'my_append_sid');
  4.  
  5. // Регистрируем первый класс
  6. $phpbb_hook->register('append_sid', array('my_append_sid_class', 'my_append_sid'));
  7.  
  8. // .. и второй класс
  9. $phpbb_hook->register('append_sid', array(&$my_second_append_sid_class, 'my_append_sid'));


С помощью этого примера вы даже сможете заставить собственные функции перехватывать самих себя:

  1. // Регистрируем ловушку, которая будет перехватываться phpbb
  2. $phpbb_hook->register('append_sid', 'my_own_append_sid');
  3.  
  4. // Добавляем функцию, которая будет перехватывать ловушки
  5. $phpbb_hook->add_hook('my_own_append_sid');
  6.  
  7. // Регистрируем ловушку, которая будет перехватываться нашей функцией
  8. $phpbb_hook->register('my_own_append_sid', 'also_my_own_append_sid');


Особая обработка / цепочки

Метод регистрации хуков способен принимать третий аргумент для определения специального режима “цепочки”. Он может принимать значения: first, last и standalone.

$phpbb_hook->register('append_sid', 'my_own_append_sid', 'first') гарантирует вызов функции в начале цепочки. Возможны вызовы более одной функции внутри первого блока — здесь используется принцип FIFO;
$phpbb_hook->register('append_sid', 'my_own_append_sid', 'last') гарантирует вызов функции в самом конце цепочки. Возможны вызовы более одной функции внутри последнего — здесь используется принцип FIFO;
$phpbb_hook->register('append_sid', 'my_own_append_sid', 'standalone') гарантирует вызов только определенной функции. Все другие функции удаляются из цепочки и другие функции не добавляются в нее после. Если два приложения пытаются переключить режим standalone, то выведется уведомление PHP, и вторая функция будет проигнорирована.
Разрешение ловушек для объектов

Т.к. система ловушек не может различать инициализированные объекты, а только оперирует самими классами, вам необходимо решать это на уровне кода.

Один из возможных способов — использование свойства:
  1. class my_hookable_object {
  2.         function blabla()
  3.         {
  4.         }
  5. }
  6.  
  7. class my_hookable_object2 extends my_hookable_object
  8. {
  9.     var $call_hook = true;
  10.  
  11.     function hook_me($my_first_parameter, $my_second_parameter)
  12.     {
  13.         if ($this->call_hook)
  14.         {
  15.             global $phpbb_hook;
  16.  
  17.             if ($phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $my_first_parameter, $my_second_parameter))
  18.             {
  19.                 if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
  20.                 {
  21.                     return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
  22.                 }
  23.             }
  24.         }
  25.  
  26.         return 'not hooked';
  27.     }
  28. }
  29.  
  30. function hooking(&$hook, $first, $second)
  31. {
  32.     return 'hooked';
  33. }
  34.  
  35. $first_object = new my_hookable_object2();
  36. $second_object = new my_hookable_object2();
  37.  
  38. $phpbb_hook->add_hook(array('my_hookable_object2', 'hook_me'));
  39.  
  40. $phpbb_hook->register(array('my_hookable_object2', 'hook_me'), 'hooking');
  41.  
  42. // Не вызывать ловушку для $first_object
  43. $first_object->call_hook = false;
  44.  
  45. echo $first_object->hook_me('first', 'second') . '<br />';
  46. echo $second_object->hook_me('first', 'second') . '<br />';
  47.  
  48. //Вывод:
  49. not hooked
  50. hooked


Другая возможность — использование переменной функции (которая может быть опущена при передачи переменных в ловушку):
  1. class my_hookable_object{
  2.     function blabla()
  3.     {
  4.     }
  5. }
  6.  
  7. class my_hookable_object2 extends my_hookable_object
  8. {
  9.     function hook_me($my_first_parameter, $my_second_parameter, $hook_me = true)
  10.     {
  11.         if ($hook_me)
  12.         {
  13.             global $phpbb_hook;
  14.  
  15.             if ($phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $my_first_parameter, $my_second_parameter))
  16.             {
  17.                 if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
  18.                 {
  19.                     return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
  20.                 }
  21.             }
  22.         }
  23.  
  24.         return 'not hooked';
  25.     }
  26. }
  27.  
  28. function hooking(&$hook, $first, $second)
  29. {
  30.     return 'hooked';
  31. }
  32.  
  33. $first_object = new my_hookable_object2();
  34. $second_object = new my_hookable_object2();
  35.  
  36. $phpbb_hook->add_hook(array('my_hookable_object2', 'hook_me'));
  37.  
  38. $phpbb_hook->register(array('my_hookable_object2', 'hook_me'), 'hooking');
  39.  
  40. echo $first_object->hook_me('first', 'second', false) . '<br />';
  41. echo $second_object->hook_me('first', 'second') . '<br />';      
  42.  
  43. // Вывод:
  44. not hooked
  45. hooked


4. Возвращение результата

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

Случай № 1 — Возвращение результата выполнения функции

Представьте себе, что следующая функция поддерживает ловушки:
  1. function append_sid($url, $params = false, $is_amp = true, $session_id = false){
  2.     global $_SID, $_EXTRA_URL, $phpbb_hook;
  3.  
  4.    
  5. // Разработчикам, использующим ловушки необходимо делать
  6. // глобальными $_SID  и $_EXTRA_URL в своих собственных
  7. // функциях и умело управлять ими.
  8.  
  9. // Большую часть кода можно просто копировать отсюда
  10. if ($phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id)){
  11.         if ($phpbb_hook->hook_return(__FUNCTION__))
  12.         {
  13.             return $phpbb_hook->hook_return_result(__FUNCTION__);
  14.         }
  15.     }
  16.  
  17.     [...]
  18. }


Теперь ваша функция. Сразу после того как вы вернете результат, функция append_sid() возвратит ваш результат:
  1. // Перехватываемая функция
  2. function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
  3. {
  4.    
  5.      // Получаем возможные результаты
  6.      $result = $hook->previous_hook_result('append_sid');
  7.  
  8.      return 'После того, как я верну что-нибудь, функция append_sid() вернет мой результат';
  9.  
  10. }


Всегда следует использовать возможность получать результаты выполнения функции выше, в методе previous_hook_result(), который возвращает массив вида array('result' => [your result]).

Случай № 2 — Вообще ничего не возвращаем

Иногда приложениям нет необходимости что-то возвращать и поэтому нижеследующие функции продолжат выполнение:
  1. function append_sid($url, $params = false, $is_amp = true, $session_id = false)
  2. {
  3.     global $_SID, $_EXTRA_URL, $phpbb_hook;
  4.  
  5.     if ($phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id))
  6.     {
  7.         if ($phpbb_hook->hook_return(__FUNCTION__))
  8.         {
  9.             return $phpbb_hook->hook_return_result(__FUNCTION__);
  10.         }
  11.     }
  12.  
  13.     [...]
  14. }
  15.  
  16. // Перехватываемая функция
  17. function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
  18. {
  19.  
  20.     // Получаем возможные результаты
  21.     $result = $hook->previous_hook_result('append_sid');
  22.  
  23.     [...]
  24.  
  25.     // Я только перезаписываю некоторые переменные и ничего не возвращаю, поэтому функция append_sid() не будет ничего возвращать.
  26. }


Обратите внимание: Решение возвращать или не возвращать делается исключительно в самом конце вызова цепочки ловушек. Например:
  1. // Перехватываемая функция
  2. function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
  3. {  
  4.  
  5.     // Получаем возможные результаты
  6.     $result = $hook->previous_hook_result('append_sid');
  7.  
  8.     // переменная $result не содержит значения
  9.    
  10.     return 'FILLED';
  11. }
  12.  
  13. // Эта функция тоже регистрируется и выполняется после  my_append_sid()
  14. function my_own_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
  15. {
  16.     $result = $hook->previous_hook_result('append_sid');
  17.  
  18.     // переменная $result заполнится 'FILLED'
  19.  
  20.    // Но, т.к. я ничего не возвращаю, то функция  append_sid()  продолжит свое выполнение
  21.  
  22. }
  23.  
  24. // Способ регистрации обеих функцих
  25. $phpbb_hook->register('append_sid', 'my_append_sid');
  26. $phpbb_hook->register('append_sid', 'my_own_append_sid');


6. Внедрение ваших файлов/классов/методов

В целом есть два способа, между которыми вы можете выбирать:

1) Добавить файл в папку includes/hooks/. Файл должен иметь префикс hook_. Этот файл подключится внутри common.php, вы можете зарегистрировать свои ловушки, подключить другие файлы или функции и т.д. Рекомендуется подключать другие файлы только, если это необходимо (например, внутри вызова функции).

Имейте ввиду, что вам нужно очистить кэш, чтобы ваши вновь перемещенные файлы были доступны phpBB3.

2) Второй способ предназначен для желающих обернуть код phpBB3, взамен размещения специального файла в папке для ловушек. Это обычно делается путем подключения файлов phpBB внутри файла приложения. Для того, чтобы зарегистрировать свою ловушку вам нужно создать в приложении функцию:
  1. // Моя функция, которая выполняется внутри конструктора
  2. function phpbb_hook_register(&$hook)
  3. {
  4.     $hook->register('append_sid', 'my_append_sid');
  5. }
  6.  
  7. [...]


Оригинал текста.
Tags:
Hubs:
Total votes 35: ↑23 and ↓12+11
Comments16

Articles