r20151125
Signed-off-by: Flashwave <me@flash.moe>
This commit is contained in:
parent
6ee42c62b5
commit
ffa83320d2
6 changed files with 448 additions and 2 deletions
52
_sakura/components/BBcode/BBcode.php
Normal file
52
_sakura/components/BBcode/BBcode.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* BBcode main
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\BBcode;
|
||||||
|
|
||||||
|
class BBcode
|
||||||
|
{
|
||||||
|
// Text
|
||||||
|
private $text;
|
||||||
|
private $seed;
|
||||||
|
|
||||||
|
// Contructor
|
||||||
|
public function __construct($text = "", $seed = '9001')
|
||||||
|
{
|
||||||
|
$this->setText($text);
|
||||||
|
$this->seed = $seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set text
|
||||||
|
public function setText($text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to storage format
|
||||||
|
public function toStore()
|
||||||
|
{
|
||||||
|
// Create new Store
|
||||||
|
$store = new Store($this->text, $this->seed);
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
$store = $store->generate();
|
||||||
|
|
||||||
|
// And return
|
||||||
|
return $store;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to storage format
|
||||||
|
public function toHTML()
|
||||||
|
{
|
||||||
|
// Create new Parse
|
||||||
|
$parse = new Parse($this->text, $this->seed);
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
$parse = $parse->parse();
|
||||||
|
|
||||||
|
// And return
|
||||||
|
return $parse;
|
||||||
|
}
|
||||||
|
}
|
140
_sakura/components/BBcode/Parse.php
Normal file
140
_sakura/components/BBcode/Parse.php
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* BBcode parser
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\BBcode;
|
||||||
|
|
||||||
|
class Parse
|
||||||
|
{
|
||||||
|
// Text
|
||||||
|
private $text;
|
||||||
|
private $seed;
|
||||||
|
|
||||||
|
// Simple bbcodes
|
||||||
|
private $simple = [
|
||||||
|
'b' => 'strong',
|
||||||
|
'i' => 'em',
|
||||||
|
'u' => 'u',
|
||||||
|
's' => 'del',
|
||||||
|
'h' => 'h2',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Advanced bbcodes
|
||||||
|
private $advanced = [
|
||||||
|
'spoiler' => '<span class="spoiler">|</span>',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct($text = "", $seed = '9001')
|
||||||
|
{
|
||||||
|
$this->setText($text);
|
||||||
|
$this->seed = $seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setText($text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseImage($text)
|
||||||
|
{
|
||||||
|
return preg_replace_callback(
|
||||||
|
"#\[img:{$this->seed}\](?<url>[^[]+)\[/img:{$this->seed}\]#",
|
||||||
|
function ($i) {
|
||||||
|
return "<img src=\"{$i['url']}\" alt=\"{$i['url']}\" />";
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseList($text)
|
||||||
|
{
|
||||||
|
$text = preg_replace("#\[list=\d+:{$this->seed}\]#", '<ol>', $text);
|
||||||
|
$text = preg_replace("#\[list(=.?)?:{$this->seed}\]#", "<ol class='unordered'>", $text);
|
||||||
|
$text = preg_replace("#\[/\*(:m)?:{$this->seed}\]\n?#", '</li>', $text);
|
||||||
|
$text = str_replace("[*:{$this->seed}]", '<li>', $text);
|
||||||
|
$text = str_replace("[/list:o:{$this->seed}]", '</ol>', $text);
|
||||||
|
$text = str_replace("[/list:u:{$this->seed}]", '</ol>', $text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseCode($text)
|
||||||
|
{
|
||||||
|
return preg_replace_callback(
|
||||||
|
"#[\r|\n]*\[code:{$this->seed}\][\r|\n]*(.*?)[\r|\n]*\[/code:{$this->seed}\][\r|\n]*#s",
|
||||||
|
function ($c) {
|
||||||
|
return '<pre class="prettyprint linenums">' . str_replace('<br />', '', $c[1]) . '</pre>';
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseQuote($text)
|
||||||
|
{
|
||||||
|
$text = preg_replace("#\[quote="([^:]+)":{$this->seed}\]#", '<h4>\\1 wrote:</h4><blockquote>', $text);
|
||||||
|
$text = str_replace("[quote:{$this->seed}]", '<blockquote>', $text);
|
||||||
|
$text = str_replace("[/quote:{$this->seed}]", '</blockquote>', $text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseSimple($text)
|
||||||
|
{
|
||||||
|
// Parse all simple tags
|
||||||
|
foreach ($this->simple as $code => $tag) {
|
||||||
|
$text = str_replace("[{$code}:{$this->seed}]", "<{$tag}>", $text);
|
||||||
|
$text = str_replace("[/{$code}:{$this->seed}]", "</{$tag}>", $text);
|
||||||
|
}
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseAdvanced($text)
|
||||||
|
{
|
||||||
|
// Parse all advanced tags
|
||||||
|
foreach ($this->advanced as $code => $tags) {
|
||||||
|
$tags = explode('|', $tags);
|
||||||
|
|
||||||
|
$text = str_replace("[{$code}:{$this->seed}]", $tags[0], $text);
|
||||||
|
$text = str_replace("[/{$code}:{$this->seed}]", $tags[1], $text);
|
||||||
|
}
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseColour($text)
|
||||||
|
{
|
||||||
|
$text = preg_replace("#\[color=([^:]+):{$this->seed}\]#", "<span style='color:\\1'>", $text);
|
||||||
|
$text = str_replace("[/color:{$this->seed}]", '</span>', $text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseUrl($text)
|
||||||
|
{
|
||||||
|
$text = preg_replace("#\[url:{$this->seed}\](.+?)\[/url:{$this->seed}\]#", "<a rel='nofollow' href='\\1'>\\1</a>", $text);
|
||||||
|
$text = preg_replace("#\[url=(.+?):{$this->seed}\]#", "<a rel='nofollow' href='\\1'>", $text);
|
||||||
|
$text = str_replace("[/url:{$this->seed}]", '</a>', $text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse()
|
||||||
|
{
|
||||||
|
// Get text
|
||||||
|
$text = $this->text;
|
||||||
|
|
||||||
|
$text = str_replace("\n", '<br />', $text);
|
||||||
|
|
||||||
|
$text = $this->parseCode($text);
|
||||||
|
$text = $this->parseList($text);
|
||||||
|
$text = $this->parseQuote($text);
|
||||||
|
|
||||||
|
$text = $this->parseAdvanced($text);
|
||||||
|
$text = $this->parseColour($text);
|
||||||
|
$text = $this->parseImage($text);
|
||||||
|
$text = $this->parseSimple($text);
|
||||||
|
$text = $this->parseUrl($text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
}
|
250
_sakura/components/BBcode/Store.php
Normal file
250
_sakura/components/BBcode/Store.php
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* BBcode storage format generator/converter
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\BBcode;
|
||||||
|
|
||||||
|
class Store
|
||||||
|
{
|
||||||
|
// Text
|
||||||
|
private $text;
|
||||||
|
private $seed;
|
||||||
|
|
||||||
|
// Special escapes
|
||||||
|
protected $escapes = [
|
||||||
|
'[' => '[',
|
||||||
|
']' => ']',
|
||||||
|
'.' => '.',
|
||||||
|
':' => ':',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Spaces
|
||||||
|
protected $spaces = [
|
||||||
|
"(^|\s)",
|
||||||
|
"((?:\.|\))?(?:$|\s|\n|\r))",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Simple bbcodes
|
||||||
|
protected $simple = [
|
||||||
|
'b',
|
||||||
|
'i',
|
||||||
|
'u',
|
||||||
|
's',
|
||||||
|
'h',
|
||||||
|
'img',
|
||||||
|
'spoiler',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
public function __construct($text = "", $seed = "")
|
||||||
|
{
|
||||||
|
$this->setText($text);
|
||||||
|
$this->seed = $seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set text
|
||||||
|
public function setText($text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colour tag
|
||||||
|
public function parseColour($text)
|
||||||
|
{
|
||||||
|
return preg_replace(
|
||||||
|
",\[(color=(?:#[[:xdigit:]]{6}|[[:alpha:]]+))\](.+?)\[(/color)\],",
|
||||||
|
"[\\1:{$this->seed}]\\2[\\3:{$this->seed}]",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align tag
|
||||||
|
public function parseAlign($text)
|
||||||
|
{
|
||||||
|
return preg_replace(
|
||||||
|
",\[(align=(?:[[:alpha:]]+))\](.+?)\[(/align)\],",
|
||||||
|
"[\\1:{$this->seed}]\\2[\\3:{$this->seed}]",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size tag
|
||||||
|
public function parseSize($text)
|
||||||
|
{
|
||||||
|
return preg_replace(
|
||||||
|
",\[(size=(?:[[:digit:]]+))\](.+?)\[(/size)\],",
|
||||||
|
"[\\1:{$this->seed}]\\2[\\3:{$this->seed}]",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple tags
|
||||||
|
public function parseSimple($text)
|
||||||
|
{
|
||||||
|
// Parse all simple tags
|
||||||
|
foreach ($this->simple as $code) {
|
||||||
|
$text = preg_replace(
|
||||||
|
"#\[{$code}](.*?)\[/{$code}\]#s",
|
||||||
|
"[{$code}:{$this->seed}]\\1[/{$code}:{$this->seed}]",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code tag
|
||||||
|
public function parseCode($text)
|
||||||
|
{
|
||||||
|
$text = preg_replace_callback(
|
||||||
|
"#\[code\](((?R)|.)*?)\[/code\]#s",
|
||||||
|
function ($t) {
|
||||||
|
$escaped = $this->escape($t[1]);
|
||||||
|
|
||||||
|
return "[code:{$this->seed}]{$escaped}[/code:{$this->seed}]";
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quote tag
|
||||||
|
public function parseQuote($text)
|
||||||
|
{
|
||||||
|
$patterns = ["/\[(quote(?:=".+?")?)\]/", '[/quote]'];
|
||||||
|
$counts = [preg_match_all($patterns[0], $text), substr_count($text, $patterns[1])];
|
||||||
|
$limit = min($counts);
|
||||||
|
|
||||||
|
$text = preg_replace($patterns[0], "[\\1:{$this->seed}]", $text, $limit);
|
||||||
|
$text = preg_replace('/' . preg_quote($patterns[1], '/') . '/', "[/quote:{$this->seed}]", $text, $limit);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseList($text)
|
||||||
|
{
|
||||||
|
$patterns = ["/\[(list(?:=.+?)?)\]/", '[/list]'];
|
||||||
|
$counts = [preg_match_all($patterns[0], $text), substr_count($text, $patterns[1])];
|
||||||
|
$limit = min($counts);
|
||||||
|
|
||||||
|
$text = str_replace('[*]', "[*:{$this->seed}]", $text);
|
||||||
|
$text = str_replace('[/*]', '', $text);
|
||||||
|
|
||||||
|
$text = preg_replace($patterns[0], "[\\1:{$this->seed}]", $text, $limit);
|
||||||
|
$text = preg_replace('/' . preg_quote($patterns[1], '/') . '/', "[/list:o:{$this->seed}]", $text, $limit);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseEmotes($text)
|
||||||
|
{
|
||||||
|
$match = [];
|
||||||
|
$replace = [];
|
||||||
|
|
||||||
|
foreach ($this->emoticons as $emote) {
|
||||||
|
$match[] = '(?<=^|[\n .])' . preg_quote($emote['code'], '#') . '(?![^<>]*>)';
|
||||||
|
$replace[] = '<!-- s' . $emote['code'] . ' --><img src="' . $emote['url'] . '" alt="' . $emote['code'] . '" /><!-- s' . $emote['code'] . ' -->';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($match)) {
|
||||||
|
$text = trim(
|
||||||
|
preg_replace(
|
||||||
|
explode(
|
||||||
|
chr(0),
|
||||||
|
'#' . implode('#' . chr(0) . '#', $match) . '#'
|
||||||
|
),
|
||||||
|
$replace,
|
||||||
|
$text
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseUrl($text)
|
||||||
|
{
|
||||||
|
$urlPattern = '(?:https?|ftp)://.+?';
|
||||||
|
|
||||||
|
$text = preg_replace_callback(
|
||||||
|
"#\[url\]({$urlPattern})\[/url\]#",
|
||||||
|
function ($m) {
|
||||||
|
$url = $this->escape($m[1]);
|
||||||
|
return "[url:{$this->seed}]{$url}[/url:{$this->seed}]";
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
|
||||||
|
$text = preg_replace_callback(
|
||||||
|
"#\[url=({$urlPattern})\](.+?)\[/url\]#",
|
||||||
|
function ($m) {
|
||||||
|
$url = $this->escape($m[1]);
|
||||||
|
return "[url={$url}:{$this->seed}]{$m[2]}[/url:{$this->seed}]";
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseLinks($text)
|
||||||
|
{
|
||||||
|
// Spaces
|
||||||
|
$spaces = ["(^|\s)", "((?:\.|\))?(?:$|\s|\n|\r))"];
|
||||||
|
|
||||||
|
// HTTP(s), FTP, IRC and osu
|
||||||
|
$text = preg_replace(
|
||||||
|
"#{$spaces[0]}((?:https?|ftp|irc|osu)://[^\s]+?){$spaces[1]}#",
|
||||||
|
"\\1<!-- m --><a href='\\2' rel='nofollow'>\\2</a><!-- m -->\\3",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
|
||||||
|
// Prefixed with www.
|
||||||
|
$text = preg_replace(
|
||||||
|
"/{$spaces[0]}(www\.[^\s]+){$spaces[1]}/",
|
||||||
|
"\\1<!-- w --><a href='http://\\2' rel='nofollow'>\\2</a><!-- w -->\\3",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
|
||||||
|
// E-mail addresses
|
||||||
|
$text = preg_replace(
|
||||||
|
"/{$spaces[0]}([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z-]+){$spaces[1]}/",
|
||||||
|
"\\1<!-- e --><a href='mailto:\\2' rel='nofollow'>\\2</a><!-- m -->\\3",
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escapes
|
||||||
|
public function escape($text)
|
||||||
|
{
|
||||||
|
return str_replace(
|
||||||
|
array_keys($this->escapes),
|
||||||
|
$this->escapes,
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generator
|
||||||
|
public function generate()
|
||||||
|
{
|
||||||
|
// Get the text
|
||||||
|
$text = htmlentities($this->text);
|
||||||
|
|
||||||
|
$text = $this->parseCode($text);
|
||||||
|
$text = $this->parseQuote($text);
|
||||||
|
$text = $this->parseList($text);
|
||||||
|
|
||||||
|
$text = $this->parseSimple($text);
|
||||||
|
$text = $this->parseAlign($text);
|
||||||
|
$text = $this->parseUrl($text);
|
||||||
|
$text = $this->parseSize($text);
|
||||||
|
$text = $this->parseColour($text);
|
||||||
|
|
||||||
|
$text = $this->parseLinks($text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ namespace Sakura\Forum;
|
||||||
use Sakura\Main;
|
use Sakura\Main;
|
||||||
use Sakura\Database;
|
use Sakura\Database;
|
||||||
use Sakura\User;
|
use Sakura\User;
|
||||||
|
use Sakura\BBcode\BBcode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Post
|
* Class Post
|
||||||
|
|
|
@ -704,7 +704,7 @@ class User
|
||||||
], ['change_id', true]);
|
], ['change_id', true]);
|
||||||
|
|
||||||
// Check if anything was returned
|
// Check if anything was returned
|
||||||
if ($getOld) {
|
if ($getOld && $getOld['user_id'] != $this->id()) {
|
||||||
return [0, 'TOO_RECENT', $getOld['change_time']];
|
return [0, 'TOO_RECENT', $getOld['change_time']];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
namespace Sakura;
|
namespace Sakura;
|
||||||
|
|
||||||
// Define Sakura version
|
// Define Sakura version
|
||||||
define('SAKURA_VERSION', '20151122');
|
define('SAKURA_VERSION', '20151125');
|
||||||
define('SAKURA_VLABEL', 'Eminence');
|
define('SAKURA_VLABEL', 'Eminence');
|
||||||
define('SAKURA_COLOUR', '#6C3082');
|
define('SAKURA_COLOUR', '#6C3082');
|
||||||
define('SAKURA_STABLE', false);
|
define('SAKURA_STABLE', false);
|
||||||
|
@ -50,6 +50,9 @@ require_once ROOT . '_sakura/components/Urls.php';
|
||||||
require_once ROOT . '_sakura/components/User.php';
|
require_once ROOT . '_sakura/components/User.php';
|
||||||
require_once ROOT . '_sakura/components/Users.php';
|
require_once ROOT . '_sakura/components/Users.php';
|
||||||
require_once ROOT . '_sakura/components/Whois.php';
|
require_once ROOT . '_sakura/components/Whois.php';
|
||||||
|
require_once ROOT . '_sakura/components/BBcode/BBcode.php';
|
||||||
|
require_once ROOT . '_sakura/components/BBcode/Parse.php';
|
||||||
|
require_once ROOT . '_sakura/components/BBcode/Store.php';
|
||||||
require_once ROOT . '_sakura/components/Forum/Forum.php';
|
require_once ROOT . '_sakura/components/Forum/Forum.php';
|
||||||
require_once ROOT . '_sakura/components/Forum/Forums.php';
|
require_once ROOT . '_sakura/components/Forum/Forums.php';
|
||||||
require_once ROOT . '_sakura/components/Forum/Post.php';
|
require_once ROOT . '_sakura/components/Forum/Post.php';
|
||||||
|
|
Reference in a new issue