Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
831 florian 1
Creating Modules for Phorum5
2
============================
3
 
4
This document describes the Phorum5 module system. It is targeted at
5
developers who want to do customization and extend the functionality
6
of Phorum5. Modules are the preferred way to archieve this in
7
Phorum5.
8
 
9
For much of this document, we will be talking about an example module
10
"foo". Of course you will not name your module "foo", but something much
11
more appropriate. If you're not familiar with the terms "foo" and "bar",
12
you can visit http://en.wikipedia.org/wiki/Metasyntactic_variable
13
 
14
Be sure to read at least the **CAUTIONS AND SECURITY ISSUES** section,
15
before making your own modules.
16
 
17
 
18
Table of contents:
19
 
20
1. Introduction
21
   1.1 Modules
22
   1.2 Hacks
23
   1.3 Hooks
24
2. Creating your own modules
25
   2.1 What modules are built of
26
       2.1.1 Hook functions
27
       2.1.2 Module information
28
       2.1.3 Other "stuff"
29
   2.2 Module structure
30
       2.2.1 Single file modules
31
       2.2.2 Multiple file modules
32
   2.3 Supporting multiple languages
33
   2.4 Storing message data
34
       2.4.1 From hooks that are run before saving a message to the database
35
       2.4.2 From other hooks
36
   2.5 Storing user data
37
   2.6 Creating custom URLs
38
   2.7 Implementing settings for your module
39
   2.8 Changing the template
40
   2.9 Example modules
41
3. **CAUTIONS AND SECURITY ISSUES**
42
   3.1 Make modules, not hacks
43
   3.2 Reload your module if you change the module information
44
   3.3 How to access the $PHORUM array from your hook functions
45
   3.4 How to access additional files in your multi file module
46
   3.5 Secure your PHP files agains hackers
47
   3.6 Secure your pages from XSS
48
   3.7 Prevent namespace collisions
49
       3.7.1 (Hook) functions
50
       3.7.2 Data stored in $PHORUM
51
       3.7.3 Language strings stored in $PHORUM
52
       3.7.4 Data stored in messages, users and settings
53
4. Overview of available Phorum hooks
54
   4.1 Code hooks
55
   4.2 Template hooks
56
5. Support
57
 
58
 
59
1. Introduction
60
-------------------------------------------------------------------------------
61
 
62
 
63
 1.1 Modules
64
 -----------
65
 
66
   Modules are self contained pieces of software, that can be added to
67
   Phorum to change or extend its functionality. Modules can do this
68
   without having to change anything in the standard Phorum distribution
69
   files or database structure. So installing a module means: drop in
70
   the code, go to the admin "Modules" page, enable the module and it
71
   works.
72
 
73
 
74
 1.2 Hacks
75
 ---------
76
 
77
   The moment it is neccessary to make changes to the standard Phorum
78
   distribution files or database structure to implement some kind of
79
   functionality, we're talking about a hack (even if the changes
80
   that have to be made are accompanied by a drop in module).
81
 
82
   Although there is nothing wrong with writing hacks, the Phorum team
83
   wants to urge you to try if you can write a module before resorting
84
   to a hack. Modules are the preferred way of modifying Phorum
85
   functionality, because that will make both upgrading your distribution
86
   and having your modification adopted by others easier.
87
 
88
 
89
 1.3 Hooks
90
 ---------
91
 
92
   Phorum uses hooks to run its modules. Hooks are points in the
93
   application where Phorum stops and runs its data through the modules
94
   that are configured to handle the hook. The modules can act upon and
95
   change this data.
96
 
97
   The following image visualizes what happens when Phorum reaches
98
   a hook point in the application, for which two modules ("foo" and
99
   "bar") have been configured.
100
 
101
 
102
     Phorum
103
   Application
104
       (1)                                (1) Phorum is running.
105
        |                                 (2) Phorum reaches the
106
        |                                     hook named "some_hook".
107
        v           Phorum                (3) Phorum sends data to
108
    some_hook >----- data ------+             the module system.
109
       (2)            (3)       |         (4) The module "foo" is run.
110
                                v         (5) The module "bar" is run.
111
                       (4) module "foo"   (6) The Phorum data (which
112
                                |             might be modified by the
113
                                v             modules) is sent back
114
                       (5) module "bar"       to Phorum.
115
                                |         (7) Phorum continues running
116
     Phorum        Modified     |             with the modified data.
117
   Application <---- data ------+
118
       (7)            (6)
119
        |
120
        |
121
        v
122
 
123
 
124
2. Creating your own modules
125
-------------------------------------------------------------------------------
126
 
127
 
128
 2.1 What modules are built of
129
 -----------------------------
130
 
131
 
132
  2.1.1 Hook functions
133
  --------------------
134
 
135
   A module contains one or more PHP functions that act as hook
136
   functions. Hook functions will receive some data in a variable
137
   from Phorum and have to return the (possibly modified) data, which
138
   will then go either back to Phorum or to the input of another module
139
   which also handles the same hook (see 1.3). So the most basic (and
140
   useless :-) hook function you could write would look somewhat like this
141
   (see 3.7 for an explanation of the naming of the function):
142
 
143
      function phorum_mod_foo_some_hook ($data) {
144
          return $data;
145
      }
146
 
147
   The exact nature of the data that is sent to the hook functions
148
   depends solely on the hook that is run. In chapter 4 of this document
149
   you will find a description of all supported hooks, including a
150
   specification of the type of data that is sent.
151
 
152
 
153
  2.1.2 Module information
154
  ------------------------
155
 
156
   For each hook that you want to handle in your module, you will have
157
   to point the module system to the function in your module that will
158
   handle the hook. Together with some other information, used for
159
   describing the module, this is stored in the module information.
160
   The module information acts as the glue between Phorum and your
161
   module.
162
 
163
   Module information is formatted using lines of plain text. Each line
164
   contains a bit of information about the module. The general format
165
   of the lines in the module information is:
166
 
167
      <type>: <data>
168
 
169
   Here is a list of the types that can be used:
170
 
171
   +--------+-----------------------------------------------------------+
172
   | <type> | <data>                                                    |
173
   +--------+-----------------------------------------------------------+
174
   | title  | This is the title for the module that is displayed in the |
175
   |        | "Modules" page of the admin interface.                    |
176
   +--------+-----------------------------------------------------------+
177
   | desc   | This is the description that is displayed along with the  |
178
   |        | title in the admin interface, to give a little more       |
179
   |        | information about the module. Using HTML in the <data>    |
180
   |        | part is allowed.                                          |
181
   +--------+-----------------------------------------------------------+
182
   | hook   | This describes which hook functions are called for which  |
183
   |        | Phorum hooks. The data consists of two fields, separated  |
184
   |        | by a pipe "|" symbol. The first field contains the name   |
185
   |        | of the hook that this module is hooking into. The second  |
186
   |        | field contains the name of the hook function that will be |
187
   |        | called for the hook.                                      |
188
   +--------+-----------------------------------------------------------+
189
 
190
   It is allowed to use multiple hook lines in your module information,
191
   so your module can hook into multiple hooks. When doing this, it
192
   is also allowed to use the same hook function for handling different
193
   hooks in your module (asuming the hooks are compatible).
194
 
195
   Here's an example of what the module information for our example
196
   module "foo" might look like:
197
 
198
      title: Foo example module
199
      desc: This is the Foo module for Phorum. Nothing exciting...
200
      hook: some_hook|phorum_mod_foo_some_hook
201
      hook: some_other_hook|phorum_mod_foo_some_other_hook
202
      hook: yet_another_hook|phorum_mod_foo_some_other_hook
203
 
204
   So what this module info for example does, is telling Phorum that
205
   when it gets to "some_other_hook", it will have to call the function
206
   phorum_mod_foo_some_other_hook() in your module. It also tells
207
   that for "yet_another_hook" the same function has to be called.
208
 
209
 
210
  2.1.3 Other "stuff"
211
  -------------------
212
 
213
   Hook functions and the module information are all the parts needed
214
   for creating a working module. However, your module might need
215
   extra stuff like template, language and image files. You can
216
   store these files along with your module when using the multiple
217
   file module structure (see 2.2.2 below).
218
 
219
   If you do not need to store any other stuff with your module, you
220
   can also choose to use the single file (see 2.2.1 below) module
221
   structure.
222
 
223
 
224
 2.2 Module structure
225
 --------------------
226
 
227
 
228
  2.2.1 Single file modules
229
  -------------------------
230
 
231
   Single file modules are useful in case case no additional files have
232
   to be distributed with your module. Because the module consist of
233
   only one single file, it is very easy to distribute. Beware that the
234
   moment you want to support for example a settings screen, multiple
235
   languages or custom images, you will have to switch to the multiple
236
   file module structure.
237
 
238
   Single file modules consist of one single PHP file, which contains
239
   both the module information and the hook functions. For storing the
240
   module informaton, a special PHP comment is used. This comment must
241
   look like the following:
242
 
243
      /* phorum module info
244
      <module information lines go here>
245
      */
246
 
247
   Using the example module info from 2.1.2, the complete single
248
   file module would look like this (see 3.5 why we use the
249
   check on PHORUM at the start of this file):
250
 
251
      <?php
252
 
253
      if(!defined("PHORUM")) return;
254
 
255
      /* phorum module info
256
      title: Foo example module
257
      desc: This is the Foo module for Phorum. Nothing exciting...
258
      hook: some_hook|phorum_mod_foo_some_hook
259
      hook: some_other_hook|phorum_mod_foo_some_other_hook
260
      hook: yet_another_hook|phorum_mod_foo_some_other_hook
261
      */
262
 
263
      function phorum_mod_foo_some_hook ($data) {
264
          // Do stuff for "some_hook".
265
          return $data;
266
      }
267
 
268
      function phorum_mod_foo_some_other_hook ($data) {
269
          // Do stuff for "some_other_hook" and "yet_another_hook".
270
          return $data;
271
      }
272
 
273
      ?>
274
 
275
   Installation of a single file module is done by putting the PHP
276
   file (e.g. foo.php) directly in the directory {phorum dir}/mods/
277
   and activating the module from the "Modules" screen in your
278
   admin interface.
279
 
280
 
281
  2.2.2 Multiple file modules
282
  ---------------------------
283
 
284
   Multiple file modules are useful in case you need additional files
285
   to be stored with your module, for example a settings screen,
286
   language files or custom images.
287
 
288
   Multiple file modules are stored in their own subdirectory below
289
   the directory {phorum dir}/mods/. So if you have a module named
290
   "foo", you will have to create a directory {phorum dir}/mods/foo/ for
291
   storing all module files.
292
 
293
   Inside this subdirectory, you will have to create a least two files.
294
   The first is a file called "info.txt". This file contains the
295
   module information for your module (see 2.1.2). The second file
296
   is the PHP file which contains the hook functions for your module.
297
   The basename of this file should be the same as the name of the
298
   module subdirectory. So for our example module "foo", you will have
299
   to create a file named "foo.php".
300
 
301
   Using the example module info from 2.1.2, the complete multiple
302
   file module would look like this (see 3.5 why we use the
303
   check on PHORUM at the start of the PHP file):
304
 
305
   info.txt:
306
 
307
      title: Foo example module
308
      desc: This is the Foo module for Phorum. Nothing exciting...
309
      hook: some_hook|phorum_mod_foo_some_hook
310
      hook: some_other_hook|phorum_mod_foo_some_other_hook
311
      hook: yet_another_hook|phorum_mod_foo_some_other_hook
312
 
313
   foo.php:
314
 
315
      <?php
316
 
317
      if(!defined("PHORUM")) return;
318
 
319
      function phorum_mod_foo_some_hook ($data) {
320
          // Do stuff for "some_hook".
321
          return $data;
322
      }
323
 
324
      function phorum_mod_foo_some_other_hook ($data) {
325
          // Do stuff for "some_other_hook" and "yet_another_hook".
326
          return $data;
327
      }
328
 
329
      ?>
330
 
331
   So far, the module has exactly same functionality as the single
332
   file module from 2.2.1. From here on, the functionality can be
333
   extended. Some of the possibilities are:
334
 
335
   - Using custom files for your module (images, classes, libs, etc.);
336
   - Letting your module support multiple languages;
337
   - Creating a settings screen for your module;
338
 
339
 
340
 2.3 Supporting multiple languages
341
 ---------------------------------
342
 
343
   (this feature is only available for the multiple file module structure)
344
 
345
   If your module includes text that will be displayed to end users,
346
   you should strongly consider making it support multiple languages.
347
   This will allow Phorum installations using another language to display
348
   output of your module in the same language, instead of the language
349
   you have written the module in.
350
 
351
   For supporting multiple languages, the first thing to do is add the
352
   following to your module information file (info.txt):
353
 
354
      hook: lang|
355
 
356
   There is no hook function configured here, because the "lang" hook
357
   is only used as a marker for Phorum. This only tells Phorum that your
358
   module supports multiple languages.
359
 
360
   Next, you must provide at least one language file with your module.
361
   Language files are stored in a subdirectory name "lang" inside your
362
   module directory. So in our sample module, the full directory would be
363
   {phorum dir}/foo/lang/. The language files must be named identical
364
   to the main language files that Phorum uses. So, to include both
365
   English and French, your module would have the following file
366
   structure below the Phorum's mods directory:
367
 
368
      foo/info.txt
369
      foo/foo.php
370
      foo/lang/english.php
371
      foo/lang/french.php
372
 
373
   The structure of your language files will be almost identical to that
374
   of the main Phorum language files. However, for your own language files
375
   it is advisable to add an extra level in the language variables, to
376
   avoid conflicts with other modules or Phorum itself. Here is an
377
   example of how you would do that:
378
 
379
      <?php
380
      $PHORUM["DATA"]["LANG"]["mod_foo"]["Hello"] = "Hello!";
381
      ?>
382
 
383
   Here, the extra inserted level is ["mod_foo"]. You can add as many
384
   lines as you need for your module. To access the above language string,
385
   from your module code you would use:
386
 
387
      $PHORUM["DATA"]["LANG"]["mod_foo"]["Hello"]
388
 
389
   From a template file, you would use:
390
 
391
      {LANG->mod_foo->Hello}
392
 
393
   In case a Phorum installation is using a language that your module
394
   does not support, Phorum will automatically attempt to fallback to
395
   English. So it is highly recommend that you include an english.php
396
   language file in all your modules. If both the current language and
397
   english.php are not found, Phorum will be unable to load a language
398
   for your module and will display empty space instead of language
399
   strings.
400
 
401
   Try to reuse strings that are already in the main Phorum language
402
   files itself. Only create custom strings when there is no alternative
403
   available. Having more text to translate is more work for everybody,
404
   especially the Phorum translators.
405
 
406
 
407
 2.4 Storing message data
408
 ------------------------
409
 
410
   If your module needs to store data along with a Phorum message,
411
   you can make use of the meta information array that is attached
412
   to each message ($message["meta"]). This array is a regular PHP
413
   array, which is stored in the database as serialized data
414
   (see http://www.php.net/serialize). Because Phorum and other modules
415
   make use of this meta data as well, you should not squash it,
416
   neither access the meta data in the database directly. Instead
417
   use the methods described in this section.
418
 
419
   Remark: because the meta data is stored as serialized data in the
420
   database, it is not possible to include data you store in there
421
   in SQL queries.
422
 
423
   When storing information in the meta data from a hook function, you
424
   can encounter two different situations, which both need a different
425
   way of handling.
426
 
427
 
428
  2.4.1 From hooks that are run before saving a message to the database
429
  ---------------------------------------------------------------------
430
 
431
   There are some hooks that send a full message structure to the
432
   hook functions, so these can change the message data before storing
433
   the message in the database. Examples are the hooks "pre_post"
434
   and "pre_edit". In this case you can simply update the meta
435
   information directly. Here's an example of how this would look
436
   in your hook function:
437
 
438
      function phorum_mod_foo_pre_post ($message) {
439
          $message["meta"]["mod_foo"]["foodata"] = "Some data";
440
          $message["meta"]["mod_foo"]["bardata"] = "Some more data";
441
          return $message;
442
      }
443
 
444
   Phorum will take care of storing the updated meta data in the database.
445
 
446
 
447
  2.4.2 From other hooks
448
  ----------------------
449
 
450
   For other hooks, the proper way to store information in the meta
451
   data is to retrieve the current meta data using phorum_db_get_message(),
452
   copy the meta data to a new message structure, make changes as needed
453
   and use phorum_db_update_message() to update the message in the
454
   database. Here is an example of how this could look in your hook
455
   function:
456
 
457
      function phorum_mod_foo_some_hook ($data) {
458
 
459
          // Somehow you get the id for the message. Here we asume
460
          // that it is stored in the $data parameter.
461
          $message_id = $data["message_id"];
462
 
463
          // Retrieve the current message data.
464
          $message = phorum_db_get_message ($message_id);
465
 
466
          // Create updated meta data.
467
          $new_message = array("meta" => $message["meta"]);
468
          $new_message["meta"]["mod_foo"]["foodata"] = "Some data";
469
          $new_message["meta"]["mod_foo"]["bardata"] = "Some more data";
470
 
471
          // Store the updated data in the database.
472
          phorum_db_update_message($message_id, $new_message);
473
 
474
          return $data;
475
      }
476
 
477
   Changing meta data for a message this way will ensure that the
478
   existing meta data is kept intact.
479
 
480
 
481
 2.5 Storing user data
482
 ---------------------
483
 
484
   If your module needs to store data along with a Phorum user,
485
   you can make use of custom profile fields. In the admin interface,
486
   under "Custom Profiles", you can add your own profile fields
487
   (see also docs/creating_custom_userfields.txt).
488
 
489
   The custom profile fields will be accessible from within the user
490
   data. E.g. if you have created a custom profile field named "foobar",
491
   the value of that field will be stored in $user["foobar"].
492
 
493
   When using a custom profile field for storing module information,
494
   you can use a separate field for each piece of data you want to
495
   store. But instead, you can also create a single field for storing
496
   a complete array of information. Phorum will automatically take care
497
   of storing this information (serialized) in the database. You only
498
   should make sure that the custom profile field is large enough to
499
   store all the data. When your module needs to store multiple fields,
500
   this is the preferred way.
501
 
502
   For storing data in the custom profile field, you can make use of the
503
   phorum_user_save() function. Below are two pieces of code which show
504
   how our example module might store data for a user (asuming $user_id
505
   is the id of the user that must be changed).
506
 
507
   When using multiple fields "mod_foo_foodata" and "mod_foo_bardata":
508
 
509
      $user = phorum_user_get($user_id);
510
      $user["mod_foo_foodata"] = "Some user data";
511
      $user["mod_foo_bardata"] = "Some more user data";
512
      phorum_user_save($user);
513
 
514
   When using a single custom field "mod_foo" for this module:
515
 
516
      $user = phorum_user_get($user_id);
517
      $user["mod_foo"] = array (
518
        "foodata" => "Some user data",
519
        "bardata" => "Some more user data"
520
      );
521
      phorum_user_save($user);
522
 
523
 
524
 2.6 Creating custom URLs
525
 -------------------------
526
 
527
   Phorum uses the function phorum_get_url() to consistenly build URLs
528
   that point to parts of Phorum. It is recommended that you use this
529
   function as well when creating links yourself, so special features
530
   and future changes will automatically be incorporated in the links
531
   you use.
532
 
533
   Here's an example of building an URL, which will open the profile
534
   for the user with user_id = 17:
535
 
536
      $url = phorum_get_url(PHORUM_PROFILE_URL, 17);
537
 
538
   The argument list that this function takes, depends on the first
539
   argument which tells Phorum what kind of URL has to be built.
540
   So when building other URLs, other arguments will probably
541
   be used.
542
 
543
   If you need to build a custom URL to link to your own module, you
544
   can use phorum_get_url() as well. The way to go is simple. You
545
   need to use PHORUM_CUSTOM_URL as the first argument and add all
546
   URL building parameters to it.
547
 
548
   The first parameter needs to be the filename of the file to link
549
   to, without the (.php) extension. The second parameter needs to
550
   be 0 or 1. If it is 1, the current forum_id is added to the URL.
551
   All other parameters are added comma separated to the URL.
552
 
553
   Here's an example of building a custom URL which links to the
554
   file "myfile.php". The URL has to have the forum_id in it and
555
   needs to contain the additional parameter "foo=bar":
556
 
557
      $url = phorum_get_url(PHORUM_CUSTOM_URL, "myfile", 1, "foo=bar");
558
 
559
 
560
 2.7 Implementing settings for your module
561
 -----------------------------------------
562
 
563
   (this feature is only available for the multiple file module structure)
564
 
565
   Some modules that you write might need to store settings for later
566
   use. For those, you can create a settings page which will be used
567
   from within the admin interface.
568
 
569
   The settings page must be put in your modules's directory by the
570
   name of "settings.php". So for our example module "foo" the file
571
   would go in {phorum dir}/mods/foo/settings.php. In the admin
572
   interface under the option "Modules", a link to the settings.php
573
   page will automatically be added if the settings.php file is
574
   available for your module.
575
 
576
   Although you can do anything you want from your settings.php script,
577
   it is recommended that you use the tools that are handed to you
578
   by Phorum for building pages and storing settings.
579
 
580
   One of those tools is a PHP object "PhorumInputForm" which
581
   can be used to create standard input forms and table displays in
582
   the admin interface. The best example here is to look at one of the
583
   modules that come with Phorum like "bbcode" or "replace".
584
 
585
   Another tool is the function phorum_db_update_settings() which can
586
   be used for storing settings in the database. To store settings using
587
   this function you do something like the following:
588
 
589
      $foo_settings["foodata"] = "Some setting data";
590
      $foo_settings["bardata"] = "Some more setting data";
591
      phorum_db_update_settings(array("mod_foo" => $foo_settings));
592
 
593
   $foo_settings can be anything you like: an array, object, string, etc.
594
   The first request after you have stored your settings, the setting
595
   data for this example will be available in $PHORUM["mod_foo"].
596
 
597
   To ensure that your settings file is only loaded from the admin
598
   interface, place this line at the top of your settings.php file
599
   (see also 3.5):
600
 
601
      if(!defined("PHORUM_ADMIN")) return;
602
 
603
 
604
 2.8 Changing the templates using template hooks
605
 -----------------------------------------------
606
 
607
 
608
  2.8.1 When to use a template hook
609
  ---------------------------------
610
 
611
   Changing the templates should be avoided as much as possible when
612
   writing a module. This will basically turn your mod into a hack,
613
   because files have to be edited for it. Inexperienced users might
614
   find it hard to install your module if they have to modify files
615
   to get it to work.
616
 
617
   If you cannot avoid changing the template, then consider to use
618
   template hooks for this. You can use these if your template change
619
   involves adding extra code to a template. The advantage is that
620
   there's only little code that has to be added to the templates,
621
   which makes things less confusing to users that want to install the
622
   module.
623
 
624
 
625
  2.8.2 How to use a template hook
626
  --------------------------------
627
 
628
   To create a template hook, you do the following:
629
 
630
   * Add "{HOOK tpl_some_hook}" to the template at an appropriate spot;
631
 
632
   * Put "hook: tpl_some_hook|phorum_mod_foo_tpl_some_hook" in your
633
     module info;
634
 
635
   * Create the hook function phorum_mod_foo_tpl_some_hook() that
636
     prints out the code that has to be placed at the position of
637
     the "{HOOK tpl_some_hook}" code the the template.
638
 
639
   If you want to pass on the data from template variables to
640
   the hook function, you can simply add the variables to the hook
641
   definition in the template. Example:
642
 
643
      {HOOK tpl_some_hook DATA1 DATA2}
644
 
645
   The hook function will get the contents of these variables passed in
646
   a single array. This can for example be useful if your template hook
647
   needs access to loop data. Example:
648
 
649
      {LOOP MESSAGES}
650
         ...
651
         {HOOK tpl_some_hook MESSAGES}
652
         ...
653
      {/LOOP MESSAGES}
654
 
655
 
656
  2.8.3 Preventing collisions in hook names
657
  -----------------------------------------
658
 
659
   You can use any name for "tpl_some_hook", but beware that your
660
   name does not collide with an already existing hook name.
661
 
662
   The easiest way to do this is use the techniques from section 3.7.
663
   As a rule of thumb, you can use the following format:
664
 
665
      tpl_mod_<modulename>_<identifier>
666
 
667
   Example: If a buttonbar is added in one of the templates for a module
668
   named "foo", the name for the hook could be "tpl_mod_foo_buttonbar".
669
 
670
 
671
 2.9 Example modules
672
 -------------------
673
 
674
   The best way of learning how to write modules is probably looking
675
   at existing module code. In your Phorum distribution's docs directory,
676
   you will find the directory example_mods. This directory contains a
677
   couple of example modules, demonstrating the features described in this
678
   document. The modules have no real functional purpose, but they might
679
   be easier to read than the real Phorum modules.
680
 
681
 
682
3. **CAUTIONS AND SECURITY ISSUES**
683
-------------------------------------------------------------------------------
684
 
685
 
686
 3.1 Make modules, not hacks
687
 ---------------------------
688
 
689
   Making modules that require database changes are discouraged and may
690
   not be accepted as an approved module. We want modules to be as
691
   transparent as possible for upgrades. Please attempt to store your
692
   data in the proper place. See chapter 2 for more information on that.
693
 
694
 
695
 3.2 Reload your module if you change the module information
696
 -----------------------------------------------------------
697
 
698
   If you are changing the module info for a module that is already
699
   activated in your Phorum installation, you must deactivate and
700
   reactivate it to have Phorum reload the changed information. For
701
   performance reasons the module information is only read when the
702
   module is activated.
703
 
704
   If you have added a new hook function to your module and it seems
705
   not to be run, it probably is because you did not do this.
706
 
707
 
708
 3.3 How to access the $PHORUM array from your hook functions
709
 ------------------------------------------------------------
710
 
711
   The $PHORUM array is in the global scope. From inside a function,
712
   you can not directly access this array. So you will have to import
713
   the $PHORUM array into your function scope. The Phorum team
714
   recommends the following method for doing this (check out the
715
   faq.txt to see why we do not use the "global" keyword):
716
 
717
      function phorum_mod_foo_some_hook ($data) {
718
          $PHORUM = $GLOBALS["PHORUM"];
719
 
720
          // Do stuff for "some_hook".
721
 
722
          return $data;
723
      }
724
 
725
 
726
 3.4 How to access additional files in your multi file module
727
 ------------------------------------------------------------
728
 
729
   All standard Phorum pages are run from the Phorum installation
730
   directory. The hook functions that you write also work from
731
   the same directory. So if you want to access files in your module
732
   directory, you will have to specify the relative path to those
733
   files. This path looks like:
734
 
735
      ./mods/<module>/<filename>
736
 
737
   So let's say that our module "foo" has a subdirectory "images"
738
   which contains "bar.gif", then we could display that image
739
   using the HTML code:
740
 
741
      <img src="./mods/foo/images/bar.gif" />
742
 
743
   Another example: let's say that there is a function library
744
   named "my_module_functions.php" in the module, which must be
745
   included from then module code, then this is done using:
746
 
747
      include("./mods/foo/my_module_functions.php");
748
 
749
 
750
 3.5 Secure your PHP files agains hackers
751
 ----------------------------------------
752
 
753
   To prevent hackers from loading your PHP module files directly, you
754
   should add the following to the start of your PHP files:
755
 
756
      if(!defined("PHORUM")) return;
757
 
758
   This will make sure that the file will only work when loaded from
759
   the Phorum application. If you are writing pages that are loaded
760
   from the admin interface (like a settings screen for your module),
761
   then use the following line instead:
762
 
763
      if(!defined("PHORUM_ADMIN")) return;
764
 
765
   This will make sure that the file will only work when loaded from
766
   the Phorum admin interface.
767
 
768
 
769
 3.6 Secure your pages from XSS
770
 ------------------------------
771
 
772
   XSS stands for cross site scripting. This means that hackers
773
   can feed HTML data to your application, which is displayed on
774
   screen without stripping or escaping the HTML data. This way
775
   it can be possible for hackers to feed malicous javascript
776
   code into the browser of users on the forum, causing a security
777
   risk. If you want to learn more about XSS, please visit
778
   http://en.wikipedia.org/wiki/XSS
779
 
780
   To prevent XSS security holes, you must take care that all
781
   user input is properly sanitized before displaying it on screen.
782
   Sanitizing can be done by either stripping all HTML from
783
   the data (e.g. using http://www.php.net/strip_tags) or by escaping
784
   all html characters (using http://www.php.net/htmlspecialchars).
785
 
786
   Example:
787
 
788
   If your module needs to display the username for a user on
789
   screen, it must not simply do:
790
 
791
       print $user["username"];
792
 
793
   Instead you must use:
794
 
795
       print htmlspecialchars($user["username"]);
796
 
797
   It's not only for security that you have to sanitize data before
798
   displaying it. You must use htmlspecialchars() to prevent some other
799
   possible problems as well. Imagine you have a user with the username
800
   "<b>ob". Without htmlspecialchars() the username would be interpreted
801
   as HTML code, possibly making the full page bold from the username on.
802
 
803
 
804
 3.7 Prevent namespace collisions
805
 --------------------------------
806
 
807
   When creating modules, you must always be aware that you are
808
   working in the same namespace as other modules and Phorum itself.
809
   This means that there is a risk of duplicate use of function
810
   and variable names. By following a couple of simple rules, you
811
   can greatly reduce this risk.
812
 
813
 
814
  3.7.1 (Hook) functions
815
  ----------------------
816
 
817
   Always construct names for your module functions like this:
818
 
819
      phorum_mod_<module name>_<identifier>
820
 
821
   So if you are writing functions for a module named "foo", all
822
   function names will look like:
823
 
824
      phorum_mod_foo_<identifier>
825
 
826
   You can use whatever you like for the <identifier> part. When writing
827
   a hook function, it is recommended to use the name of the hook for
828
   which you are writing the function (this will make clear what the
829
   function does, without having to check the module info). So in case
830
   you are writing a hook function for the hook "some_hook", the full
831
   function name would be:
832
 
833
      phorum_mod_foo_some_hook
834
 
835
   If your hook function handles multiple hooks at once, then
836
   simply use one of the hook's names as the <identifier> or make up
837
   something yourself.
838
 
839
 
840
  3.7.2 Data stored in $PHORUM
841
  ----------------------------
842
 
843
   When storing data in $PHORUM, always prepend the array key name
844
   with mod_<module name>. If your module is named "foo", do not use:
845
 
846
      $PHORUM["mydata"]
847
 
848
   but instead:
849
 
850
      $PHORUM["mod_foo_mydata"]
851
 
852
 
853
  3.7.3 Language strings stored in $PHORUM
854
  ----------------------------------------
855
 
856
   When storing your custom language strings, do not put them directly
857
   in $PHORUM["DATA"]["LANG"] like Phorum does, because that might
858
   result in conflicting language strings. Instead add an extra data level,
859
   which makes sure that your module keeps all language strings to itself.
860
 
861
   If your module is named "foo", you should store language strings in:
862
 
863
      $PHORUM["DATA"]["LANG"]["mod_foo"]
864
 
865
   See also section 2.3.
866
 
867
 
868
  3.7.4 Data stored in messages, users and settings
869
  -------------------------------------------------
870
 
871
   When using the Phorum provided ways of storing data in messages,
872
   users and settings, always prepend the data key with
873
   mod_<module name>. SO if your module is named "foo", do not use
874
   things like:
875
 
876
      $new_message["meta"]["foodata"] = "Some data";
877
      $user["foodata"] = "Some data";
878
      phorum_db_update_settings(array("settings" => $foo_settings));
879
 
880
   but instead:
881
 
882
      $new_message["meta"]["mod_foo_foodata"] = "Some data";
883
      $user["mod_foo_foodata"] = "Some data";
884
      phorum_db_update_settings(array("mod_foo" => $foo_settings));
885
 
886
   See also sections 2.4 (message data), 2.5 (user data) and 2.7 (settings).
887
 
888
 
889
4. Overview of available Phorum hooks
890
-------------------------------------------------------------------------------
891
 
892
   In this chapter you will find an overview of all available Phorum
893
   hooks and a description of what they do.
894
 
895
   Remarks:
896
 
897
   * Input is what your module function should expect as parameters.
898
 
899
   * Return is what your module function should return. Most hooks
900
     expect the same data structure as was sent. For those items,
901
     the Return is listed simply as "Same as Input".
902
 
903
   * Normally, hook functions are allowed to modify the data that was
904
     sent as input. If this is not allowed, the input data will be
905
     flagged as read-only.
906
 
907
   * In most cases the hook description will provide only one or more
908
     of the possible uses for the hook. The full leverage of each hook
909
     is only limited by the imagination of the module writer (it's
910
     as much a cliche as it is true).
911
 
912
   * It may be that you need to hook into a spot where there is
913
     currently no hook available. If that is the case, let the dev
914
     team know by posting a message in the development forum
915
     on phorum.org, explaining where and why you need an extra hook.
916
     Hooks will be added as neccessary, especially while Phorum 5
917
     is young.
918
 
919
 
920
 4.1 Code hooks
921
 --------------
922
 
923
   Code hooks are hooks that are called from within the Phorum core
924
   code. These hooks are typically used for modifying Phorum's internal
925
   datastructures.
926
 
927
 
928
   ----------------------------------------------------------------------------
929
   admin_general
930
 
931
   Where  : admin interface
932
   When   : Right before the PhorumInputForm object is shown.
933
   Input  : The PhorumInputForm object.
934
   Return : Same as Input
935
 
936
   This hook can be used for adding items to the form on the
937
   "General Settings" page of the admin interface.
938
 
939
   ----------------------------------------------------------------------------
940
   admin_file_purge
941
 
942
   Where  : admin interface, option "Purge Stale Files"
943
   When   : Right before stale files are deleted from the database.
944
   Input  : An array, containing a description of all stale files.
945
   Return : Same as Input
946
 
947
   The primary use of this hook would be to cleanup stale files, created
948
   by an alternate storage system for attachments (see after_attach and
949
   after_detach as well). The array that is passed on to the hook function
950
   contains arrays, which contain the following fields:
951
 
952
   file_id      : Internal id to reference the file.
953
   filename     : Name of the file.
954
   filesize     : Filesize in KB.
955
   add_datetime : Epoch timestamp for the time the file was created.
956
   reason       : A description why this file is considered to be stale.
957
 
958
   ----------------------------------------------------------------------------
959
   after_attach
960
 
961
   Where  : include/posting/action_attachments.php
962
   When   : Just after a file attachment is saved in the database
963
   Input  : Two part array where the first element is the message array and
964
            the second element is a file array that contains the name, size,
965
            and file_id of the newly saved file.
966
   Return : Same as Input
967
 
968
   The primary use of this hook would be for creating an alternate storage
969
   system for attachments. You would need to use the before_attach hook to
970
   remove the file data and in this hook it could be saved properly. You will
971
   need to use the file hook to retreive the file data later.
972
 
973
   ----------------------------------------------------------------------------
974
   after_detach
975
 
976
   Where  : include/posting/action_attachments.php
977
   When   : Just after a file attachment is deleted from the database
978
   Input  : Two part array where the first element is the message array and
979
            the second element is a file array that contains the name, size,
980
            and file_id of the deleted file.
981
   Return : Same as Input
982
 
983
   The primary use of this hook would be for creating an alternate storage
984
   system for attachments. Using this hook, you can delete the file from
985
   your alternate storage.
986
 
987
   ----------------------------------------------------------------------------
988
   after_header
989
 
990
   Where  : Every page, except for the admin interface pages
991
   When   : Right after the header is displayed.
992
   Input  : none
993
   Return : none
994
 
995
   This hook can be used for creating content at the end of the header,
996
   just before the main content is displayed.
997
 
998
   ----------------------------------------------------------------------------
999
   after_login
1000
 
1001
   Where  : login.php
1002
   When   : After a successful login, just before redirecting the
1003
            user to a Phorum page.
1004
   Input  : The redirection URL.
1005
   Return : Same as Input
1006
 
1007
   This hook can be used for performing tasks after a successful user
1008
   login and for changing the page to which the user will be redirected
1009
   (by returning a different redirection URL). If you need to access the
1010
   user data, then you can do this through the global $PHORUM variable.
1011
   The user data will be in $PHORUM["user"].
1012
 
1013
   ----------------------------------------------------------------------------
1014
   after_logout
1015
 
1016
   Where  : login.php
1017
   When   : After a logout, just before redirecting the user to
1018
            a Phorum page.
1019
   Input  : The redirection URL.
1020
   Return : Same as Input
1021
 
1022
   This hook can be used for performing tasks after a successful user
1023
   logout and for changing the page to which the user will be redirected
1024
   (by returning a different redirection URL). The user data will still
1025
   be availbale in $PHORUM["user"] at this point.
1026
 
1027
   ----------------------------------------------------------------------------
1028
   after_register
1029
 
1030
   Where  : register.php
1031
   When   : Right after a successful registration of a new user is done
1032
            and all confirmation mails are sent.
1033
   Input  : Array containing the user data of the user (read-only).
1034
   Return : Same as Input
1035
 
1036
   This hook can be used for performing tasks (like logging and
1037
   notification) after a successful user registration.
1038
 
1039
   ----------------------------------------------------------------------------
1040
   before_attach
1041
 
1042
   Where  : include/posting/action_attachments.php
1043
   When   : Just before a file attachment is saved in the database
1044
   Input  : Two part array where the first element is the message array and
1045
            the second element is a file array that contains the name, size
1046
            and data.
1047
   Return : Same as Input
1048
 
1049
   The primary use of this hook would be for creating an alternate storage
1050
   system for attachments. You would need to use the after_attach hook to
1051
   complete the process as you do not yet have the file_id for the file. You
1052
   will need to use the file hook to retreive the file data later.
1053
 
1054
   ----------------------------------------------------------------------------
1055
   before_editor
1056
 
1057
   Where  : posting.php
1058
   When   : Just before the message editor is displayed.
1059
   Input  : Array containing data for the message that will be shown
1060
            in the editor screen.
1061
   Return : Same as Input
1062
 
1063
   This hook can be used for changing message data, just before the editor
1064
   is displayed. This is done after escaping message data for XSS prevention
1065
   is done. So in the hook, the module writer will have to be aware that
1066
   data is escaped and that he has to escape data himself if needed.
1067
 
1068
   This hook is called every time the editor is displayed. If modifying
1069
   the message data does not have to be done on every request (for example
1070
   only on the first request when replying to a message), the module will
1071
   have to check the state the editor is in. Here's some hints on what
1072
   you could do to accomplish this:
1073
 
1074
   * Check the editor mode: this can be done by looking at the "mode" field
1075
     in the message data. This field can be one of "post", "reply" and "edit".
1076
 
1077
   * Check if it's the first request: this can be done by looking at the
1078
     $_POST array. If no field "message_id" can be found in there, the
1079
     editor is handing the first request.
1080
 
1081
   Using this, an example hook function that appends the string "FOO!"
1082
   to the subject when replying to a message (how useful ;-) could look
1083
   like this:
1084
 
1085
      function phorum_mod_foo_before_editor ($data)
1086
      {
1087
         if ($data["mode"] == "reply" && ! isset($_POST["message_id])) {
1088
             $data["reply"] = $data["reply"] . " FOO!";
1089
         }
1090
 
1091
         return $data;
1092
      }
1093
 
1094
   Beware: this hook function only changes message data before it is
1095
   displayed in the editor. From the editor, the user can still change
1096
   the data. Therefore, this hook cannot be used to control the data which
1097
   will be stored in the database. If you need that functionality, then
1098
   use the hooks pre_edit and/or pre_post instead.
1099
 
1100
   ----------------------------------------------------------------------------
1101
   before_footer
1102
 
1103
   Where  : Every page, except for the admin interface pages
1104
   When   : Right before the footer is displayed.
1105
   Input  : none
1106
   Return : none
1107
 
1108
   This hook can be used for creating content at the end of the main
1109
   content, just before the footer. It can also be used for
1110
   performing tasks that have to be executed at the end of each page.
1111
 
1112
   ----------------------------------------------------------------------------
1113
   before_register
1114
 
1115
   Where  : register.php
1116
   When   : Right before a new user is stored in the database.
1117
   Input  : Array containing the user data of the user.
1118
   Return : Same as Input
1119
 
1120
   This hook can be used for performing tasks before user registration.
1121
   This hook is useful if you want to add some data to or change some
1122
   data in the user data and to check if the user data is correct.
1123
 
1124
   When checking the registration data, the hook can set the "error" field
1125
   in the returned user data array. When this field is set after running
1126
   the hook, the registration processed will be halted and the error
1127
   will be displayed. If you created a custom form field "foo" and you
1128
   require that field to be filled in, you could create a hook function
1129
   which looks like this:
1130
 
1131
      function phorum_mod_foo_before_register ($data)
1132
      {
1133
         $myfield = trim($data['your_custom_field']);
1134
         if (empty($myfield)) {
1135
             $data['error'] = 'You need to fill in my custom field';
1136
         }
1137
 
1138
         return $data;
1139
      }
1140
 
1141
   ----------------------------------------------------------------------------
1142
   buddy_add
1143
 
1144
   Where  : pm.php
1145
   When   : Right after a buddy has been added successfully.
1146
   Input  : The user id of the buddy that has been added.
1147
   Return : Same as Input
1148
 
1149
   This hook can be used for performing actions after a buddy has been
1150
   added for a user (e.g. sending the new buddy a PM about this event,
1151
   update popularity counters, do logging, synchronizing with other
1152
   databases, etc.).
1153
 
1154
   ----------------------------------------------------------------------------
1155
   buddy_delete
1156
 
1157
   Where  : pm.php
1158
   When   : Right after a buddy has been deleted successfully.
1159
   Input  : The user id of the buddy that has been deleted.
1160
   Return : Same as Input
1161
 
1162
   This hook can be used for performing actions after a buddy has
1163
   been deleted for a user.
1164
 
1165
   ----------------------------------------------------------------------------
1166
   cc_save_user
1167
 
1168
   Where  : control.php
1169
   When   : Right before data for a user is saved in the control panel.
1170
   Input  : Array containing the user data to save.
1171
   Return : Same as Input
1172
 
1173
   This hook works the same way as the before_register hook, so you can
1174
   also use it for changing and checking the user data that will be
1175
   saved in the database. There's one difference. If you want to
1176
   check a custom field, you'll also need to check the panel which
1177
   you are on, because this hook is called from multiple panels.
1178
   The panel that you are on, will be stored in the 'panel' field
1179
   of the user data.
1180
 
1181
   If you have added a custom field to the template for the option
1182
   "Edit My Profile" in the control panel, your hook function will
1183
   look like this:
1184
 
1185
      function phorum_mod_foo_cc_save_user ($data)
1186
      {
1187
         // Only check data for the panel "user".
1188
         if ($data['panel'] != "user") return $data;
1189
 
1190
         $myfield = trim($data['your_custom_field']);
1191
         if (empty($myfield)) {
1192
             $data['error'] = 'You need to fill in my custom field';
1193
         }
1194
 
1195
         return $data;
1196
      }
1197
 
1198
   ----------------------------------------------------------------------------
1199
   check_post
1200
 
1201
   Where  : post.php
1202
   When   : Right after performing preliminary posting checks, unless
1203
            these checks have returned something bad.
1204
   Input  : Array containing:
1205
 
1206
            1 => $error, to return errors in
1207
   Return : Same as Input
1208
 
1209
   This hook can be used for modifying data in the $_POST array and for
1210
   running additional checks on the data. If an error is put in $error,
1211
   Phorum will stop posting the message and show the error to the user
1212
   in the post-form.
1213
 
1214
   Beware that $error can already contain an error on input, in case
1215
   multiple modules are run for this hook. Therefore you might want to
1216
   return immediately in your hook function in case $error is already
1217
   set.
1218
 
1219
   Below is an example of how a function for this hook could look.
1220
   This example will disallow the use of the word "bar" in the
1221
   message body.
1222
 
1223
      function phorum_mod_foo_check_post ($args) {
1224
          list ($message, $error) = $args;
1225
          if (!empty($error)) return $args;
1226
 
1227
          if (stristr($message["body"], "bar") !== false) {
1228
              return array($message, "The body may not contain 'bar'");
1229
          }
1230
 
1231
          return $args;
1232
      }
1233
 
1234
   ----------------------------------------------------------------------------
1235
   close_thread
1236
 
1237
   Where  : moderation.php
1238
   When   : Right after a thread has been closed by a moderator.
1239
   Input  : The id of the thread that has been closed (read-only).
1240
   Return : Same as Input
1241
 
1242
   This hook can be used for performing actions like sending notifications
1243
   or making log entries after closing threads.
1244
 
1245
   ----------------------------------------------------------------------------
1246
   common
1247
 
1248
   Where  : common.php, so in practice every page
1249
   When   : Right before the end of the common.php include script.
1250
   Input  : none
1251
   Return : none
1252
 
1253
   This hook can be used for applying custom settings or altering
1254
   Phorum settings based on external parameters.
1255
 
1256
   ----------------------------------------------------------------------------
1257
   common_no_forum
1258
 
1259
   Where  : common.php, so in practice every page
1260
   When   : Right after no forum settings were found, before doing the redirect
1261
   Input  : none
1262
   Return : none
1263
 
1264
   This hook can be used for returning some other message (i.e. a 404-page)
1265
   to the visitor if the requested forum was not found.
1266
 
1267
   ----------------------------------------------------------------------------
1268
   common_post_user
1269
 
1270
   Where  : common.php, so in practice every page
1271
   When   : Right after loading the user from the database, but just
1272
            before making descisions on language and template.
1273
   Input  : none
1274
   Return : none
1275
 
1276
   This hook can be used for applying custom settings or altering
1277
   Phorum settings based on external parameters.
1278
 
1279
   ----------------------------------------------------------------------------
1280
   common_pre
1281
 
1282
   Where  : common.php, so in practice every page
1283
   When   : Right after loading the settings from the database, but just
1284
            before making descisions on language, template and user.
1285
   Input  : none
1286
   Return : none
1287
 
1288
   This hook can be used for applying custom settings or altering
1289
   Phorum settings based on external parameters.
1290
 
1291
   ----------------------------------------------------------------------------
1292
   delete
1293
 
1294
   Where  : moderation.php
1295
   When   : Right after deleting a message from the database.
1296
   Input  : Array of ids for messages that have been deleted (read-only).
1297
   Return : none
1298
 
1299
   This hook can be used for cleaning up anything you may have created
1300
   with the post_post hook or any other hook that stored data tied to
1301
   messages.
1302
 
1303
   ----------------------------------------------------------------------------
1304
   external
1305
 
1306
   The external hook functions are never called from any of the standard
1307
   Phorum pages. These functions are called by invoking script.php on the
1308
   command line with the --module parameter. This can be used to pipe
1309
   output from some arbitrary command to a specific module, which can do
1310
   something with that input. If your module does not need any command
1311
   line input and is meant to be run on a regular basis, you should
1312
   consider using the scheduled hook.
1313
 
1314
   Mind that for using an external hook, the module in which it is
1315
   handled must be enabled in your admin interface. So if an external
1316
   hook is not running, the containing module might be disabled.
1317
 
1318
   To run the external hook from the command line, you have to be in
1319
   the phorum installation directory. So running the external hook of
1320
   a module named "external_foo" would be done like this on a UNIX
1321
   system prompt:
1322
 
1323
      # cd /your/phorum/dir
1324
      # php ./script.php --module=external_foo
1325
 
1326
   For easy use, you can of course put these commands in a script file.
1327
 
1328
   ----------------------------------------------------------------------------
1329
   file
1330
 
1331
   Where  : file.php
1332
   When   : When attachments are requested.
1333
   Input  : Two part array where the first element is the mime type already
1334
            detected by file.php and the second part is the file array that
1335
            contains the filename, file_data, filesize, etc.
1336
   Return : Same as Input
1337
 
1338
   This hook could be used to count file downloads, or along with after_attach
1339
   an alternate file data storage mechanism could be created.
1340
 
1341
   ----------------------------------------------------------------------------
1342
   format
1343
 
1344
   Where  : phorum_format_messages() in include/format_functions.php
1345
   When   : Everytime phorum_format_messages() is called for formatting
1346
            a message, just before it is sent to the templates.
1347
   Input  : Array of messages.
1348
   Return : Same as Input
1349
 
1350
   This hook can be used for applying custom formatting to messages. The
1351
   message fields that are most applicable for this are "body" and "author".
1352
   When writing a module using this hook, you probably want to format
1353
   those fields. In practice you can apply formatting to all the fields
1354
   you want.
1355
 
1356
   The changes you make to the messages are for displaying purposes
1357
   only, so the changes are not stored in the database.
1358
 
1359
   ----------------------------------------------------------------------------
1360
   hide
1361
 
1362
   Where  : moderation.php
1363
   When   : Right after a message has been hidden by a moderator.
1364
   Input  : The id of the message that has been hidden (read-only).
1365
   Return : Same as Input
1366
 
1367
   This hook can be used for performing actions like sending notifications
1368
   or making log entries after hiding a message.
1369
 
1370
   ----------------------------------------------------------------------------
1371
   index
1372
 
1373
   Where  : include/index_new.php and include/index_classic.php
1374
   When   : Right before the list of forums is displayed.
1375
   Input  : Array of forums.
1376
   Return : Same as Input
1377
 
1378
   This hook can be used for changing or adding data to the forums
1379
   in the list.
1380
 
1381
   ----------------------------------------------------------------------------
1382
   lang
1383
 
1384
   The lang hook is a only a 'marker'. It flags Phorum that your module
1385
   supports multiple languages. It does not take a hook function in
1386
   your module information. If you do define a hook function, it will
1387
   never be called.
1388
 
1389
   Read section 2.3 for information on the use of multiple languages.
1390
 
1391
   ----------------------------------------------------------------------------
1392
   list
1393
 
1394
   Where  : list.php
1395
   When   : Right before the messages are formatted and displayed.
1396
   Input  : Array of threads (or messages in threaded mode).
1397
   Return : Same as Input
1398
 
1399
   This hook can be used for changing or adding data to the messages
1400
   in the list.
1401
 
1402
   ----------------------------------------------------------------------------
1403
   moderation
1404
 
1405
   Where  : moderation.php
1406
   When   : At the start of moderation.php
1407
   Input  : The id of the moderation step which is run (read-only).
1408
   Return : none
1409
 
1410
   This hook can be used for logging moderator actions. You can
1411
   use the $PHORUM-array to retrieve additional info like the
1412
   moderating user's id and similar.
1413
 
1414
   The moderation step id is the variable $mod_step that is used in
1415
   moderation.php. Please read that script to see what moderation
1416
   steps are available and for what moderation actions they stand.
1417
 
1418
   When checking the moderation step id for a certain step, always use
1419
   the contstants that are defined for this in include/constants.php.
1420
   The numerical value of this id can change between Phorum releases.
1421
 
1422
   ----------------------------------------------------------------------------
1423
   move_thread
1424
 
1425
   Where  : moderation.php
1426
   When   : Right after a thread has been moved by a moderator.
1427
   Input  : The id of the thread that has been moved (read-only).
1428
   Return : none
1429
 
1430
   This hook can be used for performing actions like sending notifications
1431
   or for making log entries after moving a thread.
1432
 
1433
   ----------------------------------------------------------------------------
1434
   pm_sent
1435
 
1436
   Where  : include/controlcenter/pm.php
1437
   When   : Right after a PM and its email notifications have been sent.
1438
   Input  : Array containing the private message data (read-only).
1439
   Return : none
1440
 
1441
   This hook can be used for performing actions after sending a PM. Before
1442
   PM notification by email was put in the Phorum core, this hook was
1443
   used to send those notifications.
1444
 
1445
   ----------------------------------------------------------------------------
1446
   post_edit
1447
 
1448
   Where  : include/moderation_functions.php
1449
   When   : Right after storing an edited message in the database.
1450
   Input  : Array containing message data (read-only).
1451
   Return : none
1452
 
1453
   This hook can be used for sending notifications or for making log entries
1454
   in the database when editing takes place.
1455
 
1456
   ----------------------------------------------------------------------------
1457
   post_post
1458
 
1459
   Where  : post.php
1460
   When   : Right after storing a new message in the database and just
1461
            before the user is redirected back to the list.
1462
   Input  : Array containing message data (read-only).
1463
   Return : none
1464
 
1465
   This hook can be used for performing actions based on what the message
1466
   contained.
1467
 
1468
   ----------------------------------------------------------------------------
1469
   posting_permission
1470
 
1471
   Where  : posting.php
1472
   When   : Right after Phorum has determined all abilities that apply
1473
            to the logged in user.
1474
   Input  : none
1475
   Ouput  : none
1476
 
1477
   This hook can be used for setting up custom abilities and permissions
1478
   for users, by updating the applicable fields in $GLOBALS["PHORUM"]["DATA"]
1479
   (e.g. for giving certain users the right to make postings sticky, without
1480
   having to make the full moderator for a forum).
1481
 
1482
   Read the code in posting.php before this hook is called to find out
1483
   what fields can be used.
1484
 
1485
   Beware: Only use this hook if you know what you are doing and understand
1486
   Phorum's editor permission code. If used wrong, you can open up security
1487
   holes in your Phorum installation!
1488
 
1489
   ----------------------------------------------------------------------------
1490
   pre_edit
1491
 
1492
   Where  : include/moderation_functions.php
1493
   When   : Right before storing an edited message in the database.
1494
   Input  : Array containing message data.
1495
   Return : Same as Input
1496
 
1497
   This hook can be used for changing the message data before storing it
1498
   in the database.
1499
 
1500
   ----------------------------------------------------------------------------
1501
   pre_post
1502
 
1503
   Where  : post.php
1504
   When   : Right before storing a new message in the database.
1505
   Input  : Array containing message data.
1506
   Return : Same as Input
1507
 
1508
   This hook can be used for changing the message data before storing it
1509
   in the database.
1510
 
1511
   ----------------------------------------------------------------------------
1512
   profile
1513
 
1514
   Where  : profile.php and include/controlcenter/summary.php
1515
   When   : Right before a user profile is displayed.
1516
   Input  : Array containing user profile data.
1517
   Return : Same as Input
1518
 
1519
   This hook can be used for making changes to the profile data. This
1520
   is for displaying purposes only, so the changes are not stored in the
1521
   database.
1522
 
1523
   ----------------------------------------------------------------------------
1524
   quote
1525
 
1526
   Where  : reply.php, read.php (for inline reply form support)
1527
   When   : Right after the message to reply to has been loaded.
1528
   Input  : Array containing:
1529
 
1530
            1 => The message body
1531
   Return : The quoted body to use in the post form.
1532
 
1533
   When quoting a message for reply, by default Phorum formats quoted
1534
   messages using an old school email style of quoting. By using the quote
1535
   hook, you can implement a different quoting mechanism.
1536
 
1537
   Your hook function will retrieve an array containing two elements:
1538
   the author and the body of the message to be quoted. The return
1539
   value for your hook function must be the quoted body that will
1540
   be pre-filled into the reply form.
1541
 
1542
   The BBCode module that is distributed with Phorum has a quote hook
1543
   function. Because it does not make sense to have more than one quote
1544
   hook active, the BBCode module has an option to disable its quote hook
1545
   function. You need to make sure that its quote hook function is disabled
1546
   when using your own quote hook.
1547
 
1548
   ----------------------------------------------------------------------------
1549
   read
1550
 
1551
   Where  : read.php
1552
   When   : Right before messages are formatted for displaying.
1553
   Input  : Array of messages.
1554
   Return : Same as Input
1555
 
1556
   This hook can be used for making changes to the message data when
1557
   reading messages. This is for displaying purposes only, so the
1558
   changes are not stored in the database.
1559
 
1560
   ----------------------------------------------------------------------------
1561
   read_user_info
1562
 
1563
   Where  : read.php post.php include/moderation_functions.php
1564
   When   : Right after retrieving user data.
1565
   Input  : Array of users.
1566
   Return : Same as Input
1567
 
1568
   This hook can be used for changing information for the users before
1569
   being displayed. For example: add a border around user signatures.
1570
   This is for displaying purposes only, so the changes are not stored
1571
   in the database.
1572
 
1573
   ----------------------------------------------------------------------------
1574
   readthreads
1575
 
1576
   Where  : read.php
1577
   When   : At the start of the threaded read handling, just before
1578
            sorting and displaying the threads.
1579
   Input  : Array of messages.
1580
   Return : Same as Input
1581
 
1582
   This hook does exactly the same as the read hook, except that this
1583
   one is only applied to messages when viewing the message list in
1584
   threaded mode.
1585
 
1586
   ----------------------------------------------------------------------------
1587
   reopen_thread
1588
 
1589
   Where  : moderation.php
1590
   When   : Right after a thread has been reopened by a moderator.
1591
   Input  : The id of the thread that has been reopened (read-only).
1592
   Return : Same as Input
1593
 
1594
   This hook can be used for performing actions like sending notifications
1595
   or making log entries after reopening threads.
1596
 
1597
   ----------------------------------------------------------------------------
1598
   report
1599
 
1600
   Where  : report.php
1601
   When   : Just before a reported message is sent to the moderators.
1602
   Input  : Array with maildata (see report.php for the exact contents).
1603
   Return : Same as Input
1604
 
1605
   This hook can be used for changing the report data that will be
1606
   sent to the moderators or for performing actions like making log
1607
   entries.
1608
 
1609
   ----------------------------------------------------------------------------
1610
   sanity_checks
1611
 
1612
   Where  : include/admin/sanity_checks.php
1613
   When   : Just before the admin interface's sanity checks are run
1614
   Input  : Array with sanity checks. Each sanity check is an array with:
1615
            function    => The function that runs the sanity check
1616
            description => A description to show in the admin interface
1617
   Return : Same as Input
1618
 
1619
   This hook can be used to add custom sanity checks to the admin
1620
   interface option "System Sanity Checks".
1621
 
1622
   Each checking function is expected to return an array containing
1623
   two elements:
1624
 
1625
      [0] A status, which can be one of
1626
          PHORUM_SANITY_OK     No problem found
1627
          PHORUM_SANITY_WARN   Problem found, but no fatal one
1628
          PHORUM_SANITY_CRIT   Critical problem found
1629
 
1630
      [1] A description of the problem that was found or NULL.
1631
 
1632
   A general checking function looks like this:
1633
 
1634
      function check_foo() {
1635
         $check_ok = ...some check...;
1636
         if (!$check_ok) {
1637
            return array(PHORUM_SANITY_CRIT, "Foo went wrong because ...");
1638
         } else {
1639
            return array(PHORUM_SANITY_OK, NULL);
1640
         }
1641
      }
1642
 
1643
   ----------------------------------------------------------------------------
1644
   scheduled
1645
 
1646
   Scheduled hook functions are similar to external ones, except these
1647
   functions do not require any input from the command line. The modules
1648
   containing a scheduled hook are invoked by running script.php with
1649
   the --scheduled argument (no module name is taken; this argument
1650
   will run all scheduled hooks for all available modules).
1651
 
1652
   Like the name of the hook already suggests, this hook can be used for
1653
   creating tasks which have to be executed on a regular basis. To
1654
   archieve this, you can let script.php run from a scheduling
1655
   service (like a cron job on a UNIX system).
1656
 
1657
   In general, scheduled hooks are used for automating tasks you want
1658
   to execute without having to perform any manual action. Practical
1659
   uses for a scheduled hook could be housekeeping (cleanup of
1660
   stale/old data), daily content generation (like sending daily digests
1661
   containing all posted messages for that day) or forum statistics
1662
   generation.
1663
 
1664
   Mind that for using a scheduled hook, the module in which it is
1665
   handled must be enabled in your admin interface. So if a scheduled
1666
   hook is not running, the containing module might be disabled.
1667
 
1668
   To run the scheduled hook from the command line or from a scheduling
1669
   service, you have to be in the phorum installation directory. So
1670
   running the scheduled hooks for your Phorum installation would
1671
   be done like this on a UNIX system prompt:
1672
 
1673
      # cd /your/phorum/dir
1674
      # php ./script.php --scheduled
1675
 
1676
   When creating a scheduling service entry for running this
1677
   automatically, then remind to change the directory as well.
1678
   You might also have to use the full path to your PHP binary
1679
   (/usr/bin/php or whatever it is on your system), because
1680
   the scheduling service might not know the path to it. An entry
1681
   for the cron system on UNIX could look like this:
1682
 
1683
 
1684
 
1685
   Please refer to your system's documentation to see how to
1686
   use your system's scheduling service.
1687
 
1688
   ----------------------------------------------------------------------------
1689
   search
1690
 
1691
   Where  : search.php
1692
   When   : Right before messages are formatted for displaying.
1693
   Input  : Array of messages.
1694
   Return : Same as Input
1695
 
1696
   This hook can be used for making changes to the message data when
1697
   searching for messages. This is for displaying purposes only, so the
1698
   changes are not stored in the database.
1699
 
1700
   ----------------------------------------------------------------------------
1701
   send_mail
1702
 
1703
   Where  : include/email_functions.php in the function phorum_email_user()
1704
   When   : Right before email is sent using PHP's mail() function.
1705
   Input  : Array with maildata (read-only) containing:
1706
            addresses => Array of e-mail addresses,
1707
            from      => The sender address,
1708
            subject   => The mail subject,
1709
            body      => The mail body,
1710
            bcc       => Whether to use Bcc for mailing multiple recipients
1711
   Return : true/false - see description
1712
 
1713
   This hook can be used for implementing an alternative mail sending
1714
   system (e.g. like the SMTP module does). The hook should return true if
1715
   Phorum should still send the mails himself. If you do not want to have
1716
   Phorum send the mails also, return false.
1717
 
1718
   ----------------------------------------------------------------------------
1719
   user_list
1720
 
1721
   Where  : include/users.php include/controlcenter/groupmod.php
1722
   When   : Whenever phorum_user_get_list() is called.
1723
   Input  : Array containing:
1724
            <user_id> => <data>
1725
            Where <data> is an array containing:
1726
            username    => the username for the user
1727
            displayname => the way to display the username
1728
   Return : Same as Input
1729
 
1730
    This hook can be used for reformatting the list of users in some
1731
    way, such as changing the sort order or changing the format of
1732
    the displayed names.
1733
 
1734
 
1735
 4.2 Template hooks
1736
 ------------------
1737
 
1738
   Template hooks are called from within Phorum's template files.
1739
   These hooks can be used to extend the user interface with custom
1740
   elements. From a hook function for one of these template hooks, the
1741
   module writer can print the HTML code that has to be added to the
1742
   interface at the postition of the hook call in the template.
1743
 
1744
 
1745
   ----------------------------------------------------------------------------
1746
   tpl_editor_after_subject
1747
 
1748
   Where  : posting_messageform.tpl
1749
   When   : After the Subject: field in the message editor.
1750
   Input  : none
1751
   Return : none
1752
 
1753
   This hook can be used to add custom form fields to the message editor.
1754
   In the default template, the hook is run from within a two column table.
1755
   Column one contains the labels and column two the form fields. So your
1756
   hook function for adding a field to the editor could look like this:
1757
 
1758
      function phorum_mod_foo_tpl_editor_after_subject()
1759
      {
1760
         $value = isset($_POST["mod_foo"]) ? $_POST["mod_foo"] : "";
1761
         ?>
1762
         <tr>
1763
           <td>
1764
             Foo field
1765
           </td>
1766
           <td>
1767
             <input type="text" name="mod_foo"
1768
              value="<?php print htmlspecialchars($value) ?>"/>
1769
           </td>
1770
         </tr>
1771
         <?php
1772
      }
1773
 
1774
   ----------------------------------------------------------------------------
1775
   tpl_cc_usersettings
1776
 
1777
   Where  : cc_usersettings.tpl
1778
   When   : After the built-in usersettings fields.
1779
   Input  : Array containing the user's current profile.
1780
   Return : Same as Input
1781
 
1782
   This hook can be used to add extra fields to the settings pages in the
1783
   user's control center. Here's an example hook function that will add
1784
   an extra field to the "Edit My Profile" page.
1785
 
1786
      function phorum_mod_foo_tpl_cc_usersettings($profile)
1787
      {
1788
          // Check if we're on the userprofile page of cc_usersettings.tpl.
1789
          if (! isset($profile["USERPROFILE"]) || ! $profile["USERPROFILE"])
1790
             return;
1791
 
1792
          $value = isset($profile["shoesize"])
1793
                 ? htmlspecialchars($profile["shoesize"]) : "";
1794
          ?>
1795
          <tr>
1796
            <td>Shoe size</td>
1797
            <td><input name="shoesize" type="text" value="<?=$value?>"></td>
1798
          </tr>
1799
          <?php
1800
      }
1801
 
1802
   ----------------------------------------------------------------------------
1803
   tpl_editor_attachment_buttons
1804
 
1805
   Where  : posting_attachments_list.tpl
1806
   When   : Before the delete button for an attachment.
1807
   Input  : Array containing attachment information.
1808
   Return : Same as Input
1809
 
1810
   This hook can be used to add extra buttons to each attachment in the
1811
   editor, so you can do custom actions for attachments.
1812
 
1813
   To make your buttons look the same as Phorum's buttons, use the
1814
   CSS class "PhorumSubmit".
1815
 
1816
   Here's an example hook function that will add a button to the attachments,
1817
   which will send a javascript alert to the user when clicked.
1818
 
1819
      function phorum_mod_foo_tpl_editor_attachment_buttons($data)
1820
      {
1821
         $id = $data["file_id"];
1822
         ?>
1823
         <input type="submit" class="PhorumSubmit" value="Say it!"
1824
          onclick="alert('You clicked attachment id <?php print $id ?>')" />
1825
         <?php
1826
      }
1827
 
1828
   ----------------------------------------------------------------------------
1829
   tpl_editor_before_textarea
1830
 
1831
   Where  : posting_messageform.tpl
1832
   When   : Before the textarea.
1833
   Input  : none
1834
   Return : none
1835
 
1836
   This hook can be used to add custom user interface elements before the
1837
   textarea in the message editor.
1838
 
1839
   ----------------------------------------------------------------------------
1840
   tpl_editor_buttons
1841
 
1842
   Where  : posting_buttons.tpl
1843
   When   : Before the main editor buttons (like Preview, Post and Cancel).
1844
   Input  : none
1845
   Return : none
1846
 
1847
   This hook can be used to add extra buttons to the editor buttons.
1848
 
1849
   To make your buttons look the same as Phorum's buttons, use the
1850
   CSS class "PhorumSubmit".
1851
 
1852
   Here's an example hook function that will add a button to the editor,
1853
   which will send a javascript alert to the user when clicked.
1854
 
1855
      function phorum_mod_foo_tpl_editor_buttons()
1856
      { ?>
1857
         <input type="submit" class="PhorumSubmit" value="Say it!"
1858
          onclick="alert('Hello, foo!')" />
1859
        <?php
1860
      }
1861
 
1862
 
1863
6. Support
1864
-------------------------------------------------------------------------------
1865
 
1866
   If you have questions about creating modules for Phorum, please visit
1867
   the website http://phorum.org/ and ask the development team for help in
1868
   the Development forum.
1869