jBBCode icon indicating copy to clipboard operation
jBBCode copied to clipboard

Tags with setOptionValidator do not run uppercase tags through the validator.

Open BenFenner opened this issue 8 months ago • 3 comments

Steps to reproduce:

  1. Have these code definitions set in DefaultCodeDefinitionSet.php:
    // [color] color tag
    $builder = new CodeDefinitionBuilder('color', '<span style="color:{option}">{param}</span>');
    $builder->setUseOption(TRUE)->setOptionValidator(new \JBBCode\validators\CssColorValidator());
    array_push($this->definitions, $builder->build());

    // [size=3] font size tag
    $builder = new CodeDefinitionBuilder('size', '<font size="{option}">{param}</font>');
    $builder->setUseOption(TRUE)->setParseContent(TRUE)->setOptionValidator(new \JBBCode\validators\FontSizeValidator());
    array_push($this->definitions, $builder->build());
  1. Have these validators: CssColorValidator.php
<?php

namespace JBBCode\validators;

require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'InputValidator.php';

/**
 * An InputValidator for CSS color values. This is a very rudimentary
 * validator. It will allow a lot of color values that are invalid. However,
 * it shouldn't allow any invalid color values that are also a security
 * concern.
 *
 * @author jbowens
 * @since May 2013
 */
class CssColorValidator implements \JBBCode\InputValidator
{

  /**
   * Returns true if $input uses only valid CSS color value
   * characters.
   *
   * @param $input  the string to validate
   */
  public function validate($input) {
    return (bool) preg_match('/^[A-z0-9\-#., ()%]+$/', $input);
  }
}

FontSizeValidator.php

<?php

  namespace JBBCode\validators;

  require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'InputValidator.php';

  /**
   * An InputValidator for font size values.
   */
  class FontSizeValidator implements \JBBCode\InputValidator {

    /**
     * Returns true if $input uses a valid font size value.
     *
     * @param $input  the string to validate
     */
    public function validate($input) {
      return (bool) in_array($input, array(1, 2, 3, 4, 5, 6, 7));
    }
  }

  1. Place text like this in an appropriate test input:
[SIZE="8"]Uppercase SIZE "8"[/SIZE]
[size="8"]Lowercase SIZE "8"[/size]

[COLOR="!@$%^"]Uppercase COLOR !@$%^[/COLOR]
[color="!@$%^"]Lowercase COLOR !@$%^[/color]
  1. Notice this inconsistent output:
<font size="8">Uppercase SIZE "8"</font><br>
[size=8]Lowercase SIZE "8"[/size]<br>
<br>
<span style="color:!@$%^">Uppercase COLOR !@$%^</span><br>
[color=!@$%^]Lowercase COLOR !@$%^[/color]

BenFenner avatar Mar 19 '25 16:03 BenFenner

Proposed fix to CodeDefinition.php:

public function hasValidInputs(ElementNode $el) 
{
    if ($this->usesOption() && $this->optionValidator) {
        $att = $el->getAttribute();

        foreach($att as $name => $value){
+           $name = strtolower($name);
            if(isset($this->optionValidator[$name]) && !$this->optionValidator[$name]->validate($value)){
                return false;
            }
        }
    }

I've confirmed this works very well on my end.

Although I can imagine a different fix applied to ElementNode.php in the correct spot(s) but I am too busy to work out any unintended consequences.

BenFenner avatar Mar 19 '25 16:03 BenFenner

Oh wow, I just realized I'm on JBBCode v1.3.0 and apparently the project is on v1.4.2 right now. I had no idea...

I guess I should update my copy. If I can get around to it, I will do that. Otherwise, I guess someone else on v1.4.2 could test to see if the same problem exists. If not, of course we can close this ticket.

BenFenner avatar Mar 19 '25 17:03 BenFenner

Again, this might be entirely irrelevant because v1.4.2 exists, but for those on v1.3.0 and wanting to solve this problem, I actually took the time to look into fixing this in a more holistic may. I think this solution is preferable to the crude solution above.

ElementNode.php

  public function setTagName($tagName)
  {
-   $this->tagName = $tagName;
+   $this->tagName = strtolower($tagName);
  }

Parser.php

  protected function parseOptions($tagContent)
  {
      $buffer  = '';
      $tagName = '';
      $state   = static::OPTION_STATE_TAGNAME;
      $keys    = array();
      $values  = array();
      $options = array();

      $len  = strlen($tagContent);
      $done = false;
      $idx  = 0;

      try{
          while(!$done){
              $char = $idx < $len ? $tagContent[$idx]:null;
              switch($state){
                  case static::OPTION_STATE_TAGNAME:
                      switch($char){
                          case '=':
                              $state   = static::OPTION_STATE_VALUE;
-                             $tagName = $buffer;
+                             $tagName = strtolower($buffer);
                              $keys[]  = $tagName;
                              $buffer  = "";
                              break;
                          case ' ':
                              $state = static::OPTION_STATE_DEFAULT;
-                             $tagName = $buffer;
+                             $tagName = strtolower($buffer);
                              $buffer  = '';
                              $keys[]  = $tagName;
                              break;

                          case null:
-                             $tagName = $buffer;
+                             $tagName = strtolower($buffer);
                              $buffer  = '';
                              $keys[]  = $tagName;
                              break;
                          default:
                              $buffer .= $char;
                      }
                      break;

visitors/NestLimitVisitor.php

  public function visitElementNode(\JBBCode\ElementNode $elementNode)
  {
-    $tagName = strtolower($elementNode->getTagName());
+    $tagName = $elementNode->getTagName();

visitors/TagCountingVisitor.php

  public function visitElementNode(\JBBCode\ElementNode $elementNode)
  {
-    $tagName = strtolower($elementNode->getTagName());
+    $tagName = $elementNode->getTagName();

BenFenner avatar Mar 21 '25 16:03 BenFenner