HTML_Template_PHPLIB
[ class tree: HTML_Template_PHPLIB ] [ index: HTML_Template_PHPLIB ] [ all elements ]

Source for file Validator.php

Documentation is available at Validator.php

  1. <?php
  2. require_once 'HTML/Template/PHPLIB/Helper.php';
  3.  
  4. /**
  5. * Class to validate templates (syntax checks)
  6. *
  7. @category HTML
  8. @package  HTML_Template_PHPLIB
  9. @author   Christian Weiske <cweiske@php.net>
  10. @license  http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  11. @link     http://pear.php.net/package/HTML_Template_PHPLIB
  12. */
  13. {
  14.     /**
  15.     * Validates a template file.
  16.     * You can pass either a file name, or the file content. One of the parameters
  17.     *  needs to be !== null.
  18.     *
  19.     * @param string $strFile    Template file name to check
  20.     * @param string $strContent Template content to check
  21.     *
  22.     * @return mixed Boolean true if no errors have been found, array of
  23.     *                 errors otherwise. An error is an array with keys
  24.     *                 - 'short' (short error code, string)
  25.     *                 - 'message' (readable message)
  26.     *                 - 'line'    (line number)
  27.     *                 - 'code'    (code that caused the error)
  28.     *                 false if no file and content is given
  29.     *
  30.     * @static
  31.     */
  32.     function validate($strFile = null$strContent = null)
  33.     {
  34.         $arLines HTML_Template_PHPLIB_Helper::getLines($strFile$strContent);
  35.         if ($arLines === false{
  36.             return false;
  37.         }
  38.         $arErrors HTML_Template_PHPLIB_Validator::checkBlockDefinitions($arLines);
  39.         $arErrors array_merge(
  40.             $arErrors,
  41.             HTML_Template_PHPLIB_Validator::checkVariables($arLines)
  42.         );
  43.  
  44.         HTML_Template_PHPLIB_Validator::sortByLine($arErrors);
  45.  
  46.         return count($arErrors== 0 ? true : $arErrors;
  47.     }//function validate($strFile = null, $strContent = null)
  48.  
  49.  
  50.  
  51.     /**
  52.     * Check if all block definitions have a closing counterpart
  53.     * and if the block comments have all the required spaces
  54.     *
  55.     * @param array $arLines Array of template code lines
  56.     *
  57.     * @return array Array of errors/warnings. An error/warning is an array
  58.     *                 of several keys: message, line
  59.     *
  60.     * @static
  61.     */
  62.     function checkBlockDefinitions($arLines)
  63.     {
  64.         //Array of block definitions found.
  65.         // key is the block name, value is an array of line numbers
  66.         $arBlocks     = array();
  67.         $arBlockOpen  = array();
  68.         $arBlockClose = array();
  69.         $arErrors     = array();
  70.  
  71.         $strRegex '/<!--(\s*)(BEGIN|END)(\s*)([a-zA-Z0-9_]*)(\s*)-->/';
  72.         foreach ($arLines as $nLine => $strLine{
  73.             if (preg_match($strRegex$strLine$arMatches)) {
  74.                 //code line numbers start with 1, not 0
  75.                 $nLine $nLine + 1;
  76.  
  77.                 $strType      $arMatches[2];
  78.                 $strBlockName $arMatches[4];
  79.                 $strArName    $strType == 'BEGIN' 'arBlockOpen' 'arBlockClose';
  80.                 if ($arMatches[1== ''{
  81.                     //space missing between <!-- and BEGIN|END
  82.                     $arErrors[= array(
  83.                         'short'   => 'MISSING_SPACE',
  84.                         'message' => 'Space missing between HTML comment opening marker and ' $strType,
  85.                         'line'    => $nLine,
  86.                         'code'    => $strLine
  87.                     );
  88.                 }
  89.                 if ($arMatches[3== ''{
  90.                     //space missing between BEGIN and block name
  91.                     $arErrors[= array(
  92.                         'short'   => 'MISSING_SPACE',
  93.                         'message' => 'Space missing between ' $strType ' and block name',
  94.                         'line'    => $nLine,
  95.                         'code'    => $strLine
  96.                     );
  97.                 }
  98.                 if ($arMatches[4== ''{
  99.                     //block name missing
  100.                     $arErrors[= array(
  101.                         'short'   => 'MISSING_BLOCK_NAME',
  102.                         'message' => 'Block name missing',
  103.                         'line'    => $nLine,
  104.                         'code'    => $strLine
  105.                     );
  106.                 else {
  107.                     ${$strArName}[$strBlockName][$nLine;
  108.                     $arBlocks[= array(
  109.                         'line' => $nLine,
  110.                         'code' => $strLine,
  111.                         'name' => $strBlockName,
  112.                         'open' => $strType == 'BEGIN'
  113.                     );
  114.                 }
  115.                 if ($arMatches[5== ''{
  116.                     //space missing between block name and -->
  117.                     $arErrors[= array(
  118.                         'short'   => 'MISSING_SPACE',
  119.                         'message' => 'Space missing between block name and HTML comment end marker',
  120.                         'line'    => $nLine,
  121.                         'code'    => $strLine
  122.                     );
  123.                 }
  124.             }
  125.         }
  126.  
  127.  
  128.         /**
  129.         * Check if all open blocks have a close counterpart
  130.         */
  131.         foreach ($arBlockOpen as $strBlockName => $arLines{
  132.             if (count($arLines> 1{
  133.                 $arErrors[= array(
  134.                     'short'   => 'DUPLICATE_BLOCK',
  135.                     'message' => 'Block "' $strBlockName '" is opened'
  136.                                . ' several times on lines ' implode(', '$arLines),
  137.                     'line'    => $arLines[0],
  138.                     'code'    => $strBlockName
  139.                 );
  140.             }
  141.             if (!isset($arBlockClose[$strBlockName])) {
  142.                 $arErrors[= array(
  143.                     'short'   => 'UNFINISHED_BLOCK',
  144.                     'message' => 'Block "' $strBlockName '" is not closed.',
  145.                     'line'    => $arLines[0],
  146.                     'code'    => $strBlockName
  147.                 );
  148.             }
  149.         }
  150.         foreach ($arBlockClose as $strBlockName => $arLines{
  151.             if (count($arLines> 1{
  152.                 $arErrors[= array(
  153.                     'short'   => 'DUPLICATE_BLOCK',
  154.                     'message' => 'Block "' $strBlockName '" is closed'
  155.                                . ' several times on lines ' implode(', '$arLines),
  156.                     'line'    => $arLines[0],
  157.                     'code'    => $strBlockName
  158.                 );
  159.             }
  160.             if (!isset($arBlockOpen[$strBlockName])) {
  161.                 $arErrors[= array(
  162.                     'short'   => 'UNFINISHED_BLOCK',
  163.                     'message' => 'Block "' $strBlockName '" is closed but not opened.',
  164.                     'line'    => $arLines[0],
  165.                     'code'    => $strBlockName
  166.                 );
  167.             }
  168.         }
  169.  
  170.  
  171.         /**
  172.         * Check correct order (that begin comes before end)
  173.         */
  174.         foreach ($arBlockOpen as $strBlockName => $arLines{
  175.             if (isset($arBlockClose[$strBlockName])
  176.              && $arLines[0$arBlockClose[$strBlockName][0]{
  177.                 $arErrors[= array(
  178.                     'short'   => 'WRONG_ORDER',
  179.                     'message' => 'BEGIN of block "' $strBlockName '" defined after END.',
  180.                     'line'    => $arLines[0],
  181.                     'code'    => $strBlockName
  182.                 );
  183.             }
  184.         }
  185.  
  186.  
  187.         /**
  188.         * Check proper nesting
  189.         */
  190.         $arStack = array();
  191.         foreach ($arBlocks as $arBlock{
  192.             if ($arBlock['open']{
  193.                 $arStack[$arBlock['name'];
  194.             else {
  195.                 //closing block
  196.                 if (end($arStack== $arBlock['name']{
  197.                     //all fine
  198.                     array_pop($arStack);
  199.                 else {
  200.                     //closing block is not the expected one
  201.                     $strStackName end($arStack);
  202.                     if ($strStackName === null{
  203.                         //no open block defined -> we already handle this
  204.                     else {
  205.                         $arErrors[= array(
  206.                             'short'   => 'WRONG_NESTING',
  207.                             'message' => 'Block "' $arBlock['name''" closed,'
  208.                                        . ' but  "' $strStackName '" is still open.',
  209.                             'line'    => $arBlock['line'],
  210.                             'code'    => $arBlock['code']
  211.                         );
  212.                     }
  213.                 }
  214.             }
  215.         }
  216.  
  217.         return $arErrors;
  218.     }//function checkBlockDefinitions($arLines)
  219.  
  220.  
  221.  
  222.     /**
  223.     * Checks if the variables defined are correct
  224.     *
  225.     * @param array $arLines Array of template content lines
  226.     *
  227.     * @return array Array of error messages.
  228.     */
  229.     function checkVariables($arLines)
  230.     {
  231.         $arErrors   = array();
  232.         $strAllowed 'a-zA-Z0-9_-';
  233.         $strRegex   '/'
  234.             . '(?:'
  235.                 . '(\{)'
  236.                 . '(['  $strAllowed ']+)'
  237.                 . '([^' $strAllowed ']|$)'
  238.             . '|'
  239.                 . '([^' $strAllowed ']|^)'
  240.                 . '(['  $strAllowed ']+)'
  241.                 . '(\})'
  242.             . ')'
  243.             . '/';
  244.         $arLineMatches = array();
  245.         foreach ($arLines as $n => $strLine{
  246.             if (preg_match_all($strRegex$strLine$arMatches> 0{
  247.                 $arLineMatches[$n + 1$arMatches;
  248.             }
  249.         }
  250.         foreach ($arLineMatches as $nLine => $arMatches{
  251.             foreach ($arMatches[0as $nId => $strFull{
  252.                 $chOpen      $arMatches[1][$nId];
  253.                 $strVariable $arMatches[2][$nId];
  254.                 $chClose     $arMatches[3][$nId];
  255.  
  256.                 if ($chOpen != '{'{
  257.                     $arErrors[= array(
  258.                         'short'   => 'OPENING_BRACE_MISSING',
  259.                         'message' => 'Variable "' $strVariable '" misses opening brace.',
  260.                         'line'    => $nLine,
  261.                         'code'    => $strFull
  262.                     );
  263.                 else if ($chClose != '}'{
  264.                     $arErrors[= array(
  265.                         'short'   => 'CLOSING_BRACE_MISSING',
  266.                         'message' => 'Variable "' $strVariable '" misses closing brace.',
  267.                         'line'    => $nLine,
  268.                         'code'    => $strFull
  269.                     );
  270.                 }
  271.             }
  272.         }
  273.  
  274.         return $arErrors;
  275.     }//function checkVariables($strContent)
  276.  
  277.  
  278.  
  279.     /**
  280.     * Sorts the given error array by line numbers
  281.     *
  282.     * @param array &$arErrors Error array
  283.     *
  284.     * @return void 
  285.     */
  286.     function sortByLine(&$arErrors)
  287.     {
  288.         if (!is_array($arErrors)) {
  289.             return;
  290.         }
  291.         usort($arErrorsarray(__CLASS__'intcmpLine'));
  292.     }//function sortByLine(&$arErrors)
  293.  
  294.  
  295.  
  296.     /**
  297.     * Compares the two error arrays by line number
  298.     *
  299.     * @param array $arA Error array one
  300.     * @param array $arB Error array two
  301.     *
  302.     * @return integer -1, 0 or 1 if $arA is smaller, equal or bigger than $arB
  303.     */
  304.     function intcmpLine($arA$arB)
  305.     {
  306.         return $arA['line'$arB['line'];
  307.     }//function intcmpLine($arA, $arB)
  308.  
  309. }//class HTML_Template_PHPLIB_Validator
  310.  
  311. ?>

Documentation generated on Mon, 11 Mar 2019 15:10:14 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.