home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / Comanche / docs / developer / addingApacheModulesForComanche.txt next >
Text File  |  2000-11-02  |  14KB  |  401 lines

  1.  
  2. Introduction
  3. ------------
  4.  
  5. This documents gives detailed information of the steps involved in adding
  6. support for a new Apache module in Comanche (like PHP3, mod_ldap, etc.) or
  7. adding support for new directives.
  8. Comanche is a framework to build management modules (plugins). There are
  9. plugins for Apache, Samba, etc.  Since Apache is a complex program the
  10. plugin itself is modular and support for directives and modules is done via
  11. an extension mechanism. 
  12. The process is relatively simple. You have to write a few XML files
  13. following certain simple rules and that's about it :)
  14.  
  15. What the Apache plugin needs to know from you
  16. ---------------------------------------------
  17.  
  18. In order to add support for your module or directive the Apache plugin needs
  19. to know a few things. 
  20.  
  21. * Where is your module located?
  22. At plugins/apache/modules you can find current supported modules each one of
  23. them has a subdirectory which contains the necessary files
  24.  
  25. * Which files are necessary to support your module?
  26. moduleDescription.xml:  Describes the module and gives pointers for the other files
  27.  
  28. directives.xml: Describes the directives that we are configuring 
  29.  
  30. propertyPages.xml: Arrange the directives for presentation to the user
  31.  
  32. specialCases.tcl: For parsing complex directives back and forth between the
  33. XML format and httpd.conf format
  34.  
  35.  
  36. moduleDescription.xml
  37. ---------------------
  38. * Description of module: name, where to find directive and property pages
  39. definition, special cases definition and description of the module
  40. * Nodes in which we are interested: Which nodes (main server, virtual
  41. hosts, etc) we want our property pages to appear in
  42. * Description of special cases: Apache uses httpd.conf format and Comanche
  43. uses XML format. If the directives are simple, the mapping will be
  44. automagically done by Comanche, if not we specify the name of the procedures
  45. here
  46.  
  47. specialCases.tcl
  48. ----------------
  49. * Actual Tcl code used to convert from XML format to httpd.conf
  50.  
  51. directives.xml
  52. --------------
  53. * Description of the directives that belong to this module
  54.  
  55. propertyPages.xml
  56. -----------------
  57. * Description of the property pages for this modules. They are presented to
  58. the user during configuration. They arrange the directives on the screen
  59. logically. It is possible to have different versions for beginners and for
  60. advanced users.
  61.  
  62.  
  63. messages
  64. --------
  65. In the subdirectory messages/ the texts corresponding to the messages are
  66. stored there so they can easily be translated by other people. The messages
  67. are stored with a suffix corresponding to the language:
  68. messages.en
  69. messages.es
  70. etc.
  71.  
  72.  
  73. Step by step guide to create a module from scratch
  74. --------------------------------------------------
  75.  
  76. The following is a detailed description of the necessary steps to add
  77. support for a module. We will add support for the PHP scripting language
  78. (http://www.php.net). 
  79.  
  80.  
  81. Planning
  82. --------
  83. We take a look at the configuration information for PHP:
  84. http://www.php.net/manual/configuration.php3
  85.  
  86. As it turns out PHP can be configured in different ways, either inside the
  87. Apache httpd.conf file or in a separate file. The syntax varies too from
  88. PHP3 to PHP4. Since this is just an example, we will configure PHP3 for
  89. httpd.conf syntax. The user interface will remain unchanged among all of
  90. them, so to support the other versions we just need to change the
  91. translating functions since as can reuse the directive and property pages
  92. definitions.
  93.  
  94. One thing to remember is that we do not need to support all directives at
  95. once. Directives not known to Comanche are safely ignored and restored when
  96. writing the output configuration file. We can provide support for the most
  97. commonly used directives and then go for the more obscure parameters.
  98.  
  99. Before doing any coding we need to plan what the user interface is going to
  100. look like. We plan on having the following property pages:
  101.  
  102. PHP3   (Enable/disable and tags)
  103.   |
  104.   \__ Resources (Limit use if resources CPU/Time)
  105.   |
  106.   \__ Error Handling (Error logs, display, etc.)
  107.   |
  108.   \__ Data Handling (POST variables, prepend, autopend...)
  109.   |
  110.   \__ Paths (auto include directories)
  111.   
  112.   
  113. Next step is to actually define the directives. The XML language used here
  114. is described in the programmer guide. It is really easy so you probably can
  115. pick it up just by taking a look at how the other modules are described.
  116. Most directives have a one to one correspondence, others will need more
  117. elaborated XML directives.
  118.  
  119. * asp_tags
  120.  
  121. In the docs we find
  122.  
  123. "asp_tags boolean
  124.  
  125. Enables the use of ASP-like <% %> tags in addition to the
  126. usual <?php ?> tags. This includes the variable-value printing shorthand of
  127. <%=$value %>. For more information, see Escaping from HTML."
  128.  
  129. It is clear that this maps directly into the XML boolean type so we write:
  130. <boolean name="php3_asp_tags" label="php_asp_tags">
  131.     <default>0</default>
  132. </boolean>       
  133.  
  134. Name is php3_asp_tags because this is how it will appear on Apache config
  135. files. This way Apache already nows which httpd.conf directives match to
  136. which XML directives.
  137. Instead of writting the description of the directive directly on the label
  138. we store the description in the messages/ subdirectory. The contents of the
  139. messages.en file:
  140. php_asp_tags {Enable ASP (<% %>) style tags?}
  141.   
  142. If we want an additional Spanish version, we write (lenguage can be later on
  143. selected by the user) 
  144. messages.es:
  145. php_asp_tags {Permitir tags como las de ASP (<% %>)?}
  146.  
  147.  
  148. * max_execution_time
  149.  
  150. This one, which accepts a number as an argument gets turned into
  151.  
  152. <number name="php3_max_execution_time" label="php_max_execution_time">
  153. <default>30</default>
  154. </number>         
  155.  
  156. with messages.en
  157. php_max_execution_time {Limit in execution time (seconds)}  
  158.  
  159.  
  160. * doc_root
  161.  
  162. This one sets the document root for safe mode. This is a string, more
  163. precisely a directory, so the corresponding entry:
  164.  
  165. <string name="php3_doc_root" label="php_doc_root" classes="directory" >
  166. <default></default>
  167. </string>
  168.  
  169. (note the classes attribute, it hints the gui to provide a directory selector
  170. button and to write back quoted directories with blank spaces)
  171.  
  172. with messages.en:
  173. php_doc_root {PHP root directory (for safe mode)}   
  174.  
  175. * gpc_order
  176.  
  177. This one could have been modeled in a different way, but this ones works
  178. just fine at it is clear
  179.  
  180. <choice name="php3_gpc_order" label="php_gpc_order">
  181.     <syntax>
  182.         <option name="GPC" value="GET/POST/COOKIE" />
  183.         <option name="GCP" value="GET/COOKIE/POST" />
  184.         <option name="PGC" value="POST/GET/COOKIE" />
  185.         <option name="PCG" value="POST/COOKIE/GET" />
  186.         <option name="CPG" value="COOKIE/POST/GET" />
  187.         <option name="CGP" value="COOKIE/GET/POST" />
  188.         <option name="GP" value="GET/POST" />
  189.         <option name="GC" value="GET/COOKIE" />
  190.         <option name="PG" value="POST/GET" />
  191.         <option name="PC" value="POST/COOKIE" />
  192.         <option name="CP" value="COOKIE/POST" />
  193.         <option name="CG" value="COOKIE/GET" />
  194.         <option name="G" value="GET" />
  195.         <option name="P" value="POST" />
  196.         <option name="C" value="COOKIE" />
  197.     </syntax>
  198.     <default>GPC</default>
  199. </choice>     
  200.  
  201. messages.en:
  202. php_gpc_order {Order of GET/POST/COOKIE variable parsing}  
  203.  
  204. So far the mapping between httpd.conf and XML directives has been pretty
  205. straightforward. For the previous entries the conversion is handled
  206. automatically by Comanche and we do not need to do anything else!
  207.  
  208. Now comes the interesting part. It requires a little bit more of work but it
  209. pays off in a more easy to use interface for the user. There are some
  210. directives that could be better expressed in some other way.
  211. Take for example the directive auto_append_file (File to always parse
  212. after processing the main file). It can have a special value of 'none' to
  213. disable this feature. Instead of mapping it to a string and have the user
  214. know that piece of information we make it a little bit easier and provide
  215. a pair of radiobuttons. First one is simply 'none' the other is the name of
  216. the file. 
  217.  
  218.  This, translated to XML gets us:
  219.  
  220.  <alternate name="php3_auto_append_file" label="php_auto_append_file"
  221.             style="normal">
  222.     <syntax>
  223.         <label name="none" label="php_auto_append_file_none" />
  224.         <string name="file" label="php_auto_append_file_file" classes="file" />
  225.     </syntax>
  226.     <default>none</default>
  227. </alternate>     
  228.     
  229.  You get the idea. By default the 'none' element is selected.
  230.  
  231. We need a way to convert from httpd.conf to this XML format and the other
  232. way around. This involves a little bit of programming, which is shown below
  233.  
  234. # This procedure is called whenever the php3_auto_append_file is encountered
  235. # in httpd.conf
  236.  
  237. proc ::apache1.3::parse_php3_auto_append_file {text parser dirDef xmlConf currentContainer} {
  238.  
  239.     # Create a new instance of this directive or overwrite the existing one
  240.     
  241.     set xuiObj [apacheparserutils::getOrCreateIfNotExists php3_auto_append_file \
  242.             $dirDef $xmlConf $currentContainer]
  243.         
  244.     # Depending on the value (none or a filename), select the appropriate component and store the value
  245.         
  246.     set value [lindex $text 1]
  247.     switch [string tolower $value] {
  248.        none {
  249.           $xuiObj selectComponentByName none
  250.        } default {
  251.           $xuiObj selectComponentByName file
  252.           $xuiObj.file setValue $value
  253.        }
  254.     }
  255. }
  256.  
  257.  
  258. # Procedure called to dump the contents to httpd.conf
  259.  
  260. proc ::apache1.3::dump_php3_auto_append_file {xuiObj} {
  261.     set value [[$xuiObj getSelectedComponent] getValue]
  262.     return "php3_auto_append_file $value" 
  263. }
  264.  
  265. Similar goes for php3_auto_prepend directive or php3_error_log
  266.  
  267.  
  268. php3_include_path
  269. -----------------
  270. This is another directive that would benefit of special treatment is
  271. php3_include_path (and php3_open_basedir)
  272.  
  273. From the PHP docs:
  274. include_path string
  275.  
  276. Specifies a list of directories where the require(), include() and
  277. fopen_with_path() functions look for files. The format is like the system's 
  278.  
  279. PATH environment variable: a list of directories separated with a colon in
  280. UNIX or semicolon in Windows. 
  281.  
  282. Example 3-1. UNIX include_path
  283.  
  284. include_path=.:/home/httpd/php-lib
  285.  
  286.  
  287. Example 3-2. Windows include_path
  288.  
  289. include_path=".;c:\www\phplib"
  290.  
  291. The default value for this directive is . (only the current directory).
  292.  
  293.  
  294. - Now we could map this directive to a string directive and hvae the user
  295. enter a string of directories separated by : or ;  Instead we make it a
  296. little bit easier for them by abstracting it and presenting them with a list
  297. of directories.
  298.  
  299. The XML description:
  300.  
  301. <list name="php3_include_path" label="php_include_path">
  302.     <syntax>
  303.         <string name="php3_include_path_file" label="php_include_path_file" classes="directory" />
  304.     </syntax>
  305.     <default>
  306.     <item>.</item>
  307.     </default>
  308. </list>
  309.  
  310. We need now a couple of functions for converting from : or ; format
  311. (httpd.conf) to XML and viceversa.
  312.  
  313. proc ::apache1.3::parse_php3_include_path {text parser dirDef xmlConf
  314. currentContainer} {
  315.     set xuiObj [apacheparserutils::getOrCreateIfNotExists php3_include_path \
  316.             $dirDef $xmlConf $currentContainer]
  317.     global tcl_platform
  318.     switch $tcl_platform(platform) {
  319.        windows {
  320.            set separator {;}
  321.        } default {
  322.            set separator :
  323.        }
  324.     }
  325.     foreach element [split [lrange $text 1 end] $separator] {
  326.         set child [$xuiObj newChild]
  327.  
  328.         # Split fscks up quoted filenames, so this is required
  329.  
  330.         regsub {\\\"} $element {"} result
  331.         $child setValue $result
  332.         $xuiObj insertChild $child
  333.     }
  334. }
  335.  
  336.  
  337. proc ::apache1.3::dump_php3_include_path {xuiObj} {
  338.    global tcl_platform
  339.    switch $tcl_platform(platform) {
  340.        windows {
  341.            set separator {;}
  342.        } default {
  343.            set separator :
  344.        }
  345.     }
  346.     set values {}
  347.     foreach child [$xuiObj getChildren] {
  348.         lappend values [$child getValue]
  349.     }
  350.     set result [join $values $separator]
  351.     if [llength $result] {
  352.         return "php3_include_path $result"
  353.     }
  354.     return {}
  355. }   
  356.  
  357.  
  358. Once we have described all the directives (take a look at
  359. plugins/apache/modules/php3/directives.xml for a complete listing)
  360. We need to tell Comanche how do we want them organized in property pages
  361. (like in the tree described at the beginning)
  362.  
  363. In plugins/apache/modules/php3/propertyPages.xml
  364.  
  365. As an example, the main page:
  366.  
  367. <propertyPage label="php3_pp_phpEngine" icon="smallWheel" name="pp_phpEngine" align="vertical">
  368.         <directiveInclude name="php3_engine"/>
  369.         <group name="php3_pp_phpEngine_tags"align="vertical"label="php3_pp_phpEngine_tags" style="normal">
  370.             <directiveInclude name="php3_asp_tags"/>
  371.             <directiveInclude name="php3_short_open_tag"/>
  372.         </group>
  373. </propertyPage>   
  374.  
  375.  
  376. Finally, the moduleDescription.xml puts everything together:
  377.  
  378. <apacheModuleDescription name="php3"
  379.                          directivesXMLDefinition="directives.xml"
  380.                          propertyPagesXMLDefinition="propertyPages.xml"
  381.                          description="PHP3 Apache module." >
  382.     <nodesInterested>
  383.         <node type="mainserver,virtualhost">
  384.              <propertyPage name="pp_phpEngine"  />
  385.  
  386.         [...]
  387.  
  388.              <propertyPage name="pp_phpPaths" hookUnder="pp_phpEngine" />
  389.         </node>
  390.     </nodesInterested>
  391.  <specialCases file="specialCases.tcl">
  392.         <specialCase confDir="php3_open_basedir"
  393.                      xmlDir="php3_open_basedir"
  394.                      parser="apache1.3::parse_php3_open_basedir"
  395.                      dumper="apache1.3::dump_php3_open_basedir" />
  396.      
  397.      [...]
  398.  
  399. </specialCases>
  400. </apacheModuleDescription>    
  401.