Scripts

dom bouwen

Met deze DOM-bouwer kan je programmatisch eenvoudig een HTML5 structuur bouwen. Het werkt zonder DOMDocument of andere XML-extentie en is daardoor portable. Het geeft geen onnodige spaties die tot CSS-problemen kunnen leiden en correcte escaping is eenvoudig. Voor unicode escaping wordt gebruik gemaakt van de grapheme_X() functies van de Intl-extentie, maar die zijn eenvoudig aan te passen naar mbstring of wat anders. Voorbeeldgebruik:

dom.php
<?php

declare (strict_types=1);


/**
 * Basisklasse helpt objecten identificeren en voorkomt tikfouten
 */

abstract class basis
{
  /** Trigger foutmelding */
  protected function fout($k)
  {
    trigger_error('Eigenschap "' . $k . '" van object "'
      . get_class($this) . '" bestaat niet of is niet publiek.');
  }

  /** Voorkomt magic getter */
  function __get(string $k)
  {
    $this->fout($k);
  }

  /** Voorkomt magic setter */
  function __set(string $k, $v)
  {
    $this->fout($k);
  }

}

/**
 * Supersimpele DOM-bouwer die openstaandetags sluit
 * Niet nodig: DOMDocument, html_X-functies en output buffer
 */

class dom extends basis
{
  /** @var string $buffer uitvoerbuffer */
  protected $buffer;

  /** @var array $tags stapel voor open tags */
  protected $tags;

  /** Constructor */
  function __construct(string $doctype)
  {
    $this->buffer = $doctype;
    $this->tags = []; 
  }

  /** of een tag andere tags kan bevatten */
  protected function is_gesloten(string $naam) : bool
  {
    return in_array($naam, ["area", "base", "br", "col", "command", "embed",
      "hr", "img", "input", "keygen", "link", "meta", "param", "source",
      "track", "wbr"]);
  }

  /** voeg het begin van een tag toe aan de uitvoerbuffer */
  protected function schrijf_tag_start(string $naam)
  {
    $this->buffer .= "<" . $naam;
  }

  /** voeg het einde van een tag toe aan de uitvoerbuffer */
  protected function schrijf_tag_sluit_direct()
  {
    $this->buffer .= ">";  // voor pure XML werd "/>" gebruikt
  }

  /** voeg attributen toe aan de uitvoerbuffer */
  protected function schrijf_tag_attributen(array $attr)
  {
    foreach ($attr as $index => $waarde) {
      $this->buffer .= " " . $index . "=\"" . $this->escape($waarde) . "\"";
    }
  }

  /** voeg het einde van een tag toe aan de uitvoerbuffer en laat open */
  protected function schrijf_tag_open()
  {
    $this->buffer .= ">";
  }

  /** voeg een tag met tekst toe aan de uitvoerbuffer */
  protected function schrijf_tag_tekst(string $naam, string $tekst)
  {
    if ($naam != "script" && $naam != "style" ) {
      $this->buffer .= $this->escape($tekst);
    } else {
      $this->buffer .= $tekst;
    }
  }

  /** sluit een openstaande tag af in de uitvoerbuffer */
  protected function schrijf_tag_sluit(string $naam)
  {
    $this->buffer .= "</" . $naam . ">";
  }

  /** escape html entiteiten (unicode veilig) */
  function escape(string $tekst) : string
  {
    $esc = "";
    $lengte = grapheme_strlen($tekst);
    for ($offset = 0; $offset < $lengte; $offset++) {
      $c = grapheme_substr($tekst, $offset, 1);
      switch ($c) {
        case "&": $esc .= "&amp;"; break;
        case "\"": $esc .= "&quot;"; break;
        case "'": $esc .= "&apos;"; break;
        case "<": $esc .= "&lt;"; break;
        case ">": $esc .= "&gt;"; break;
        default: $esc .= $c;
        
      }
    }
    return $esc;
  }

  /** escape javascript literal */
  function js_escape_literal($tekst) : string
  {
    return str_replace("'", "\'", str_replace("\\", "\\\\", $tekst));
  }

  /** voeg tag toe aan uitvoerbuffer */
  function tag(string $naam) : Self
  {
    $this->schrijf_tag_start($naam);
    if ($this->is_gesloten($naam)) {
      $this->schrijf_tag_sluit_direct();
    } else {
      $this->schrijf_tag_open();
      $this->schrijf_tag_sluit($naam);
    }
    return $this;
  }

  /** voeg een tag met tekst toe aan de uitvoerbuffer */
  function tag_tekst(string $naam, string $tekst) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_open();
    $this->schrijf_tag_tekst($naam, $tekst);
    $this->schrijf_tag_sluit($naam);
    return $this;
  }

  /** voeg een tag met attributen toe aan de uitvoerbuffer */
  function tag_attr(string $naam, array $attr) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_attributen($attr);
    if ($this->is_gesloten($naam)) {
      $this->schrijf_tag_sluit_direct();
    } else {
      $this->schrijf_tag_open();
      $this->schrijf_tag_sluit($naam);
    }
    return $this;
  }

  /** voeg een tag met attributen en tekst toe aan de uitvoerbuffer */
  function tag_attr_tekst(string $naam, array $attr, string $tekst) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_attributen($attr);
    $this->schrijf_tag_open();
    $this->schrijf_tag_tekst($naam, $tekst);
    $this->schrijf_tag_sluit($naam);
    return $this;
  }

  /** voeg een tag toe aan de uitvoerbuffer en laat deze open */
  function tag_in(string $naam) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_open();
    array_push($this->tags, $naam);
    return $this;
  }

  /** voeg een tag met tekst toe aan de uitvoerbuffer en laat deze open */
  function tag_tekst_in(string $naam, string $tekst) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_open();
    $this->schrijf_tag_tekst($naam, $tekst);
    array_push($this->tags, $naam);
    return $this;
  }

  /** voeg een tag met attributen toe aan de uitvoerbuffer en laat deze open */
  function tag_attr_in(string $naam, array $attr) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_attributen($attr);
    $this->schrijf_tag_open();
    array_push($this->tags, $naam);
    return $this;
  }

  /** voeg een tag met attributen en tekst toe aan de uitvoerbuffer en laat deze
    * open */
  function tag_attr_tekst_in(string $naam, array $attr, string $tekst) : Self
  {
    $this->schrijf_tag_start($naam);
    $this->schrijf_tag_attributen($attr);
    $this->schrijf_tag_open();
    $this->schrijf_tag_tekst($naam, $tekst);
    array_push($this->tags, $naam);
    return $this;
  }

  /** voeg tekst toe aan de uitvoerbuffer */
  function tekst(string $tekst) : Self
  {
    $this->buffer .= $this->escape($tekst);
    return $this;
  }

  /** voeg een XML-fragment toe aan de uitvoerbuffer */
  function fragment(string $xml) : Self
  {
    $this->buffer .= $xml;
    return $this;
  }

  /** sluit de meest recent openstaande tag in de uitvoerbuffer (FIFO) */
  function uit() : Self
  {
    if (count($this->tags) == 0) {
      trigger_error("DEBUG: geen openstaande tags", E_USER_WARNING);
      return $this;
    }
    $naam = array_pop($this->tags);
    $this->schrijf_tag_sluit($naam);
    return $this;
  }

  /** sluit alle openstaande stags en print de uitvoerbuffer */
  function teken() : String
  {
    while (count($this->tags) > 0) {
      $this->buffer .= "</" . array_pop($this->tags) . ">";
    }
    header('Content-Type: text/html; charset=utf-8'); 
    print $this->buffer;
  }

}

Reacties

0
Nog geen reacties.