Parcourir la source

Bring bbcode parser in as a hard dependency, and remove all default tags and unrequired features from it

staging
Parent
révision
07cb55dcab
6 fichiers modifiés avec 495 ajouts et 4 suppressions
  1. +32
    -0
      app/Helper/BBCode.php
  2. +2
    -3
      app/Knockout/Post.php
  3. +373
    -0
      app/Vendor/BBCode/BBCode.php
  4. +21
    -0
      app/Vendor/BBCode/LICENSE
  5. +67
    -0
      app/Vendor/BBCode/Tag.php
  6. +0
    -1
      composer.json

+ 32
- 0
app/Helper/BBCode.php Voir le fichier

@@ -0,0 +1,32 @@
<?php

namespace App\Helper;
use App\Vendor\BBCode\BBCode as Parser;

//use ChrisKonnertz\BBCode\BBCode as Parser;

class BBCode {

private $parser;
private $content;

public function __construct($content)
{
$this->parser = new Parser();
$this->content = $content;
$this->defineTags();
}

private function defineTags()
{
$this->parser->addTag('b', function($tag, &$html, $openingTag) {
return $openingTag ? '<strong>' : '</strong>';
});
}

public function render()
{
return $this->parser->render($this->content);
}

}

+ 2
- 3
app/Knockout/Post.php Voir le fichier

@@ -2,8 +2,8 @@

namespace App\Knockout;

use App\Helper\BBCode;
use Carbon\Carbon;
use ChrisKonnertz\BBCode\BBCode;

class Post {

@@ -38,8 +38,7 @@ class Post {

public function render()
{
$bbcode = new BBCode();
return $bbcode->render($this->content);
return (new BBCode($this->content))->render();
}

}

+ 373
- 0
app/Vendor/BBCode/BBCode.php Voir le fichier

@@ -0,0 +1,373 @@
<?php

namespace App\Vendor\BBCode;

use Closure;

/*
* BBCode to HTML converter
*
* Inspired by Kai Mallea (kmallea@gmail.com)
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*/
class Bbcode {

/**
* The text with BBCodes
*
* @var string|null
*/
protected $text = null;

/**
* Array with custom tag Closures
*
* @var Closure[]
*/
protected $customTagClosures = array();

/**
* Array of (name of) tags that are ignored
*
* @var string[]
*/
protected $ignoredTags = array();


/**
* BBCode constructor.
*
* @param string|null $text The text - might include BBCode tags
*/
public function __construct($text = null)
{
$this->setText($text);
}

/**
* Set the raw text - might include BBCode tags
*
* @param string $text The text
* @retun void
*/
public function setText($text)
{
$this->text = $text;
}

/**
* Renders only the text without any BBCode tags.
*
* @param string $text Optional: Render the passed BBCode string instead of the internally stored one
* @return string
*/
public function renderPlain($text = null)
{
if ($this->text !== null and $text === null) {
$text = $this->text;
}

return preg_replace("/\[(.*?)\]/is", '', $text);
}

/**
* Renders only the text without any BBCode tags.
* Alias for renderRaw().
*
* @deprecated Deprecated since 1.1.0
*
* @param string $text Optional: Render the passed BBCode string instead of the internally stored one
* @return string
*/
public function renderRaw($text = null)
{
return $this->renderPlain($text);
}

/**
* Renders BBCode to HTML
*
* @param string $text Optional: Render the passed BBCode string instead of the internally stored one
* @param bool $escape Escape HTML entities? (Only "<" and ">"!)
* @param bool $keepLines Keep line breaks by replacing them with <br>?
* @return string
*/
public function render($text = null, $escape = true, $keepLines = true)
{
if ($this->text !== null and $text === null) {
$text = $this->text;
}

$html = '';
$len = mb_strlen($text);
$inTag = false; // True if current position is inside a tag
$inName = false; // True if current pos is inside a tag name
$inStr = false; // True if current pos is inside a string
/** @var Tag|null $tag */
$tag = null;
$openTags = array();

/*
* Loop over each character of the text
*/
for ($i = 0; $i < $len; $i++) {
$char = mb_substr($text, $i, 1);

if ($keepLines) {
if ($char == "\n") {
$html .= '<br/>';
}
if ($char == "\r") {
continue;
}
}

if (! $escape or ($char != '<' and $char != '>')) {
/*
* $inTag == true means the current position is inside a tag definition
* (= inside the brackets of a tag)
*/
if ($inTag) {
if ($char == '"') {
if ($inStr) {
$inStr = false;
} else {
if ($inName) {
$tag->valid = false;
} else {
$inStr = true;
}
}
} else {
/*
* This closes a tag
*/
if ($char == ']' and ! $inStr) {
$inTag = false;
$inName = false;

if ($tag->valid) {
$code = null;

if ($tag->opening) {
$code = $this->generateTag($tag, $html, null, $openTags);
} else {
$openingTag = $this->popTag($openTags, $tag);
if ($openingTag) {
$code = $this->generateTag($tag, $html, $openingTag, $openTags);
}
}

if ($code !== null and $tag->opening) {
$openTags[$tag->name][] = $tag;
}

$html .= $code;
}
continue;
}

if ($inName and ! $inStr) {
/*
* This makes the current tag a closing tag
*/
if ($char == '/') {
if ($tag->name) {
$tag->valid = false;
} else {
$tag->opening = false;
}
} else {
/*
* This means a property starts
*/
if ($char == '=') {
if ($tag->name) {
$inName = false;
} else {
$tag->valid = false;
}
} else {
$tag->name .= mb_strtolower($char);
}
}
} else { // If we are not inside the name we are inside a property
$tag->property .= $char;
}
}
} else {
/*
* This opens a tag
*/
if ($char == '[') {
$inTag = true;
$inName = true;
$tag = new Tag();
$tag->position = mb_strlen($html);
} else {
$html .= $char;
}
}
} else {
$html .= htmlspecialchars($char);
}
}

/*
* Check for tags that are not closed and close them.
*/
foreach ($openTags as $name => $openTagsByType) {
$closingTag = new Tag($name, false);

foreach ($openTagsByType as $openTag) {
$html .= $this->generateTag($closingTag, $html, $openTag);
}
}

return $html;
}

/**
* Generates and returns the HTML code of the current tag
*
* @param Tag $tag The current tag
* @param string $html The current HTML code passed by reference - might be altered!
* @param Tag|null $openingTag The opening tag that is linked to the tag (or null)
* @param Tag[] $openTags Array with tags that are opned but not closed
* @return string
*/
protected function generateTag(Tag $tag, &$html, Tag $openingTag = null, array $openTags = [])
{
$code = null;

if (in_array($tag->name, $this->ignoredTags)) {
return $code;
}

// Custom tags:
foreach ($this->customTagClosures as $name => $closure) {
if ($tag->name === $name) {
$code .= $closure($tag, $html, $openingTag);
}
}

return $code;
}

/**
* Magic method __toString()
*
* @return string
*/
public function __toString()
{
return $this->render();
}

/**
* Returns the last tag of a given type and removes it from the array.
*
* @param Tag[] $tags Array of tags
* @param Tag $tag Return the last tag of the type of this tag
* @return Tag|null
*/
protected function popTag(array &$tags, $tag)
{
if (! isset($tags[$tag->name])) {
return null;
}

$size = sizeof($tags[$tag->name]);

if ($size === 0) {
return null;
} else {
return array_pop($tags[$tag->name]);
}
}

/**
* Adds a custom tag (with name and a Closure)
*
* Example:
*
* $bbcode->addTag('example', function($tag, &$html, $openingTag) {
* if ($tag->opening) {
* return '<span class="example">';
* } else {
* return '</span>';
* }
* });
*
* @param string $name The name of the tag
* @param Closure $closure The Closure that renders the tag
* @return void
*/
public function addTag($name, Closure $closure)
{
$this->customTagClosures[$name] = $closure;
}

/**
* Remove the custom tag with the given name
*
* @param string $name
* @return void
*/
public function forgetTag($name)
{
unset($this->customTagClosures[$name]);
}

/**
* Add a tag to the array of ignored tags
*
* @param string $name The name of the tag
* @return void
*/
public function ignoreTag($name)
{
if (! in_array($name, $this->ignoredTags)) {
$this->ignoredTags[] = $name;
}
}

/**
* Remove a tag from the array of ignored tags
*
* @param string $name The name of the tag
* @return void
*/
public function permitTag($name)
{
$key = array_search($name, $this->ignoredTags);

if ($key !== false) {
unset($this->ignoredTags[$key]);
}
}

/**
* Returns an array with the name of the tags that are ignored
*
* @return string[]
*/
public function getIgnoredTags()
{
return $this->ignoredTags;
}

/**
* Returns true if $haystack ends with $needle
*
* @param string $haystack
* @param string $needle
* @return bool
*/
protected function endsWith($haystack, $needle)
{
return ($needle === '' or mb_substr($haystack, -mb_strlen($needle)) === $needle);
}
}

+ 21
- 0
app/Vendor/BBCode/LICENSE Voir le fichier

@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 Chris Konnertz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 67
- 0
app/Vendor/BBCode/Tag.php Voir le fichier

@@ -0,0 +1,67 @@
<?php

namespace App\Vendor\BBCode;

/**
* This class represents a single BBCode tag.
* It is just a simple class used for storing tag.
*
* @package ChrisKonnertz\BBCode
*/
class Tag {

/**
* The name of the tag
*
* @var string|null
*/
public $name = null;

/**
* The value of the property
*
* @var string
*/
public $property = null;

/**
* Is this an opening tag (true)?
*
* @var bool
*/
public $opening = true;

/**
* Is this tag valid?
*
* @var bool
*/
public $valid = true;

/**
* Position of this tag inside the whole BBCode string
*
* @var int
*/
public $position = -1;

/**
* Tag constructor.
*
* @param string|null $name The name of the tag
* @param bool $opening Is this an opening tag (true)?
*/
public function __construct($name = null, $opening = true)
{
if ($name !== null and ! is_string($name)) {
throw new \InvalidArgumentException('The "name" parameter has to be of type string');
}
if (! is_bool($opening)) {
throw new \InvalidArgumentException('The "opening" parameter has to be of type bool');
}

$this->name = $name;
$this->opening = $opening;
}

}

+ 0
- 1
composer.json Voir le fichier

@@ -6,7 +6,6 @@
"type": "project",
"require": {
"php": "^7.4",
"chriskonnertz/bbcode": "^1.1",
"laravel/lumen-framework": "^8.0",
"nesbot/carbon": "^2.43"
},


Chargement…
Annuler
Enregistrer