Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
File diff suppressed because it is too large.
Load diff
+33
-26
@@ -11,16 +11,23 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use DOMDocument;
|
||||
use DOMNode;
|
||||
use DOMNodeList;
|
||||
use function defined;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOM Parser
|
||||
*/
|
||||
class _DOMParser
|
||||
class DOMParser
|
||||
{
|
||||
/**
|
||||
* @brief Callback to parse a DOMElement object
|
||||
@@ -35,12 +42,12 @@ class _DOMParser
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* @param string $value Contents to parse
|
||||
* @param callback $elementParser Callback to parse a DOMElement object. Is expected to call `$parent->appendChild( $element )` after doing any parsing and call `$parser->_parseDomNodeList()`. `function ( \DOMElement $element, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @param callback|NULL $textParser Callback to parse a DOMText object. Is expected to call `$parent->appendChild( $element )` after doing any parsing. `function ( \DOMText $textNode, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @param string $value Contents to parse
|
||||
* @param callback $elementParser Callback to parse a DOMElement object. Is expected to call `$parent->appendChild( $element )` after doing any parsing and call `$parser->_parseDomNodeList()`. `function ( \DOMElement $element, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @param callback|null $textParser Callback to parse a DOMText object. Is expected to call `$parent->appendChild( $element )` after doing any parsing. `function ( \DOMText $textNode, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @return string
|
||||
*/
|
||||
public static function parse( $value, $elementParser, $textParser = NULL )
|
||||
public static function parse( string $value, callable $elementParser, callable $textParser = NULL ): string
|
||||
{
|
||||
$content = static::getDocumentBodyContents( ( new static( $elementParser, $textParser ) )->parseValueIntoDocument( $value ) );
|
||||
|
||||
@@ -54,11 +61,11 @@ class _DOMParser
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param callback $elementParser Callback to parse a DOMElement object. Is expected to call `$parent->appendChild( $element )` after doing any parsing and call `$parser->_parseDomNodeList()`. `function ( \DOMElement $element, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @param callback|NULL $textParser Callback to parse a DOMText object. Is expected to call `$parent->appendChild( $element )` after doing any parsing. `function ( \DOMText $textNode, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @return string
|
||||
* @param callback $elementParser Callback to parse a DOMElement object. Is expected to call `$parent->appendChild( $element )` after doing any parsing and call `$parser->_parseDomNodeList()`. `function ( \DOMElement $element, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @param callback|null $textParser Callback to parse a DOMText object. Is expected to call `$parent->appendChild( $element )` after doing any parsing. `function ( \DOMText $textNode, \DOMNode $parent, \IPS\Text\DOMParser $parser )`
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $elementParser, $textParser = NULL )
|
||||
public function __construct( callable $elementParser, callable $textParser = NULL )
|
||||
{
|
||||
$this->elementParser = $elementParser;
|
||||
$this->textParser = $textParser;
|
||||
@@ -67,10 +74,10 @@ class _DOMParser
|
||||
/**
|
||||
* Parse Value into DOMDocument
|
||||
*
|
||||
* @param string $value Contents to parse
|
||||
* @return \DOMDocument
|
||||
* @param string $value Contents to parse
|
||||
* @return \IPS\Xml\DOMDocument
|
||||
*/
|
||||
public function parseValueIntoDocument( $value )
|
||||
public function parseValueIntoDocument( string $value ): \IPS\Xml\DOMDocument
|
||||
{
|
||||
/* Load the value into a DOMDocument */
|
||||
$source = new \IPS\Xml\DOMDocument( '1.0', 'UTF-8' );
|
||||
@@ -89,11 +96,11 @@ class _DOMParser
|
||||
/**
|
||||
* Parse DOMNode
|
||||
*
|
||||
* @param \DOMNode $node The node from the source document to parse
|
||||
* @param \DOMNode $parent The node from the new document which will be this node's parent
|
||||
* @param DOMNode $node The node from the source document to parse
|
||||
* @param DOMNode $parent The node from the new document which will be this node's parent
|
||||
* @return void
|
||||
*/
|
||||
public function _parseDomNode( \DOMNode $node, \DOMNode &$parent )
|
||||
public function _parseDomNode( DOMNode $node, DOMNode &$parent ) : void
|
||||
{
|
||||
switch ( $node->nodeType )
|
||||
{
|
||||
@@ -150,11 +157,11 @@ class _DOMParser
|
||||
/**
|
||||
* Loop child nodes of a node and parse them
|
||||
*
|
||||
* @param \DOMNodeList $children The child nodes from the source document
|
||||
* @param \DOMNode $parent The node from the new document which will be the parent of all these nodes
|
||||
* @param DOMNodeList $children The child nodes from the source document
|
||||
* @param DOMNode $parent The node from the new document which will be the parent of all these nodes
|
||||
* @return void
|
||||
*/
|
||||
public function _parseDomNodeList( \DOMNodeList $children, \DOMNode $parent )
|
||||
public function _parseDomNodeList( DOMNodeList $children, DOMNode $parent ) : void
|
||||
{
|
||||
foreach ( $children as $child )
|
||||
{
|
||||
@@ -165,10 +172,10 @@ class _DOMParser
|
||||
/**
|
||||
* Get body contents from document
|
||||
*
|
||||
* @param \DOMDocument $document The document
|
||||
* @return string
|
||||
* @param DOMDocument $document The document
|
||||
* @return DOMNode|null
|
||||
*/
|
||||
public static function getDocumentBody( \DOMDocument $document )
|
||||
public static function getDocumentBody( DOMDocument $document ): ?DOMNode
|
||||
{
|
||||
return $document->getElementsByTagName('body')->item(0);
|
||||
}
|
||||
@@ -176,14 +183,14 @@ class _DOMParser
|
||||
/**
|
||||
* Get body contents from document
|
||||
*
|
||||
* @param \DOMDocument $document The document
|
||||
* @param DOMDocument $document The document
|
||||
* @return string
|
||||
*/
|
||||
public static function getDocumentBodyContents( \DOMDocument $document )
|
||||
public static function getDocumentBodyContents( DOMDocument $document ): string
|
||||
{
|
||||
if ( $body = static::getDocumentBody( $document ) )
|
||||
{
|
||||
return \substr( $document->saveHTML( $body ), 6, -7 );
|
||||
return substr( $document->saveHTML( $body ), 6, -7 );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+36
-27
@@ -11,62 +11,71 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use AesCtr;
|
||||
use IPS\Settings;
|
||||
use function defined;
|
||||
use function function_exists;
|
||||
use function in_array;
|
||||
use function substr;
|
||||
use const IPS\TEXT_ENCRYPTION_KEY;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypted
|
||||
*/
|
||||
class _Encrypt
|
||||
class Encrypt
|
||||
{
|
||||
/**
|
||||
* Get Key
|
||||
*
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public static function key()
|
||||
public static function key() : string
|
||||
{
|
||||
return \IPS\TEXT_ENCRYPTION_KEY ?: md5( \IPS\Settings::i()->sql_pass . \IPS\Settings::i()->sql_database );
|
||||
return TEXT_ENCRYPTION_KEY ?: md5( Settings::i()->sql_pass . Settings::i()->sql_database );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cipher
|
||||
*/
|
||||
public $cipher;
|
||||
public ?string $cipher = NULL;
|
||||
|
||||
/**
|
||||
* @brief IV
|
||||
*/
|
||||
protected $iv = NULL;
|
||||
protected ?string $iv = NULL;
|
||||
|
||||
/**
|
||||
* @brief Tag
|
||||
*/
|
||||
protected $tag = NULL;
|
||||
protected ?string $tag = NULL;
|
||||
|
||||
/**
|
||||
* @brief Hash of cipher
|
||||
*/
|
||||
protected $hmac = NULL;
|
||||
protected ?string $hmac = NULL;
|
||||
|
||||
/**
|
||||
* From plaintext
|
||||
*
|
||||
* @param string $plaintext Plaintext
|
||||
* @param string $plaintext Plaintext
|
||||
* @return static
|
||||
*/
|
||||
public static function fromPlaintext( $plaintext )
|
||||
public static function fromPlaintext( string $plaintext ): static
|
||||
{
|
||||
$obj = new static;
|
||||
|
||||
/* Try to use OpenSSL if it's available... */
|
||||
if ( \function_exists( 'openssl_get_cipher_methods' ) )
|
||||
if ( function_exists( 'openssl_get_cipher_methods' ) )
|
||||
{
|
||||
/* If GCM is available (PHP 7.1+), use that as if provides authenticated encryption natively */
|
||||
if ( \in_array( 'aes-128-gcm', openssl_get_cipher_methods() ) )
|
||||
if ( in_array( 'aes-128-gcm', openssl_get_cipher_methods() ) )
|
||||
{
|
||||
$obj->iv = openssl_random_pseudo_bytes( openssl_cipher_iv_length( 'aes-128-gcm' ) );
|
||||
$obj->cipher = openssl_encrypt( $plaintext, 'aes-128-gcm', static::key(), 0, $obj->iv, $obj->tag );
|
||||
@@ -74,7 +83,7 @@ class _Encrypt
|
||||
}
|
||||
|
||||
/* Otherwise, use CBC and store the hash so we can do our own authentication when decrypting */
|
||||
elseif ( \in_array( 'aes-128-cbc', openssl_get_cipher_methods() ) )
|
||||
elseif ( in_array( 'aes-128-cbc', openssl_get_cipher_methods() ) )
|
||||
{
|
||||
$obj->iv = openssl_random_pseudo_bytes( openssl_cipher_iv_length( 'aes-128-cbc' ) );
|
||||
$obj->cipher = openssl_encrypt( $plaintext, 'aes-128-cbc', static::key(), OPENSSL_RAW_DATA, $obj->iv );
|
||||
@@ -85,20 +94,20 @@ class _Encrypt
|
||||
|
||||
/* If we're still here, fallback to the PHP library */
|
||||
require_once \IPS\ROOT_PATH . '/system/3rd_party/AES/AES.php';
|
||||
$obj->cipher = \AesCtr::encrypt( $plaintext, static::key(), 256 );
|
||||
$obj->cipher = AesCtr::encrypt( $plaintext, static::key(), 256 );
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* From plaintext
|
||||
*
|
||||
* @param string $cipher Cipher
|
||||
* @param string|null $iv The IV, or if null, will use the PHP library rather than built-in openssl_*() methods
|
||||
* @param string|null $tag The tag if using AES-128-GCM
|
||||
* @param string|null $hash The hash if using AES-128-CBC
|
||||
* @param string $cipher Cipher
|
||||
* @param string|null $iv The IV, or if null, will use the PHP library rather than built-in openssl_*() methods
|
||||
* @param string|null $tag The tag if using AES-128-GCM
|
||||
* @param string|null $hash The hash if using AES-128-CBC
|
||||
* @return static
|
||||
*/
|
||||
public static function fromCipher( $cipher, $iv = NULL, $tag = NULL, $hash = NULL )
|
||||
public static function fromCipher( string $cipher, string $iv = NULL, string $tag = NULL, string $hash = NULL ): static
|
||||
{
|
||||
$obj = new static;
|
||||
$obj->cipher = $cipher;
|
||||
@@ -111,10 +120,10 @@ class _Encrypt
|
||||
/**
|
||||
* From tag
|
||||
*
|
||||
* @param string $tag Tag
|
||||
* @param string $tag Tag
|
||||
* @return static
|
||||
*/
|
||||
public static function fromTag( $tag )
|
||||
public static function fromTag( string $tag ): static
|
||||
{
|
||||
if ( preg_match( '/^\[\!AES128GCM\[(.+?)\]\[(.+?)\]\[(.+?)\]\]/', $tag, $matches ) )
|
||||
{
|
||||
@@ -125,7 +134,7 @@ class _Encrypt
|
||||
$cipher = base64_decode( $matches[1] );
|
||||
$ivLength = openssl_cipher_iv_length('aes-128-cbc');
|
||||
|
||||
return static::fromCipher( \substr( $cipher, $ivLength + 32 ), \substr( $cipher, 0, $ivLength ), NULL, \substr( $cipher, $ivLength, 32 ) );
|
||||
return static::fromCipher( substr( $cipher, $ivLength + 32 ), substr( $cipher, 0, $ivLength ), NULL, substr( $cipher, $ivLength, 32 ) );
|
||||
}
|
||||
elseif ( preg_match( '/^\[\!AES\[(.+?)\]\]/', $tag, $matches ) )
|
||||
{
|
||||
@@ -142,7 +151,7 @@ class _Encrypt
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tag()
|
||||
public function tag(): string
|
||||
{
|
||||
if ( $this->tag )
|
||||
{
|
||||
@@ -157,7 +166,7 @@ class _Encrypt
|
||||
return '[!AES[' . $this->cipher . ']]';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypt
|
||||
*
|
||||
@@ -184,7 +193,7 @@ class _Encrypt
|
||||
else
|
||||
{
|
||||
require_once \IPS\ROOT_PATH . '/system/3rd_party/AES/AES.php';
|
||||
return \AesCtr::decrypt( $this->cipher, $keyToUse, 256 );
|
||||
return AesCtr::decrypt( $this->cipher, $keyToUse, 256 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,16 +10,19 @@
|
||||
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Data\Store;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition caching for HTML Purifier not on disk
|
||||
*/
|
||||
class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
class HtmlPurifierDefinitionCache extends HTMLPurifier_DefinitionCache
|
||||
{
|
||||
/**
|
||||
* Adds a definition object to the cache
|
||||
@@ -28,7 +31,7 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return bool
|
||||
*/
|
||||
public function add($def, $config)
|
||||
public function add( mixed $def, mixed $config): bool
|
||||
{
|
||||
return $this->set( $def, $config );
|
||||
}
|
||||
@@ -40,24 +43,24 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return bool
|
||||
*/
|
||||
public function set($def, $config)
|
||||
public function set( mixed $def, mixed $config): bool
|
||||
{
|
||||
/* If invalid type, just return */
|
||||
if( !$this->checkDefType( $def ) )
|
||||
{
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Generate key and store it */
|
||||
$key = $this->generateKey( $config );
|
||||
|
||||
\IPS\Data\Store::i()->$key = base64_encode( \serialize( $def ) );
|
||||
Store::i()->$key = base64_encode( serialize( $def ) );
|
||||
|
||||
/* Store an array of all keys so we can implement flush() and cleanup() */
|
||||
$currentKeys = \IPS\Data\Store::i()->htmlpurifier_definitions;
|
||||
$currentKeys = Store::i()->htmlpurifier_definitions;
|
||||
$currentKeys[ $key ] = $key;
|
||||
|
||||
\IPS\Data\Store::i()->htmlpurifier_definitions = $currentKeys;
|
||||
Store::i()->htmlpurifier_definitions = $currentKeys;
|
||||
|
||||
/* Return TRUE */
|
||||
return TRUE;
|
||||
@@ -70,7 +73,7 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return bool
|
||||
*/
|
||||
public function replace($def, $config)
|
||||
public function replace( mixed $def, mixed $config): bool
|
||||
{
|
||||
return $this->set( $def, $config );
|
||||
}
|
||||
@@ -81,13 +84,13 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return mixed FALSE if not found, or the definition object
|
||||
*/
|
||||
public function get($config)
|
||||
public function get( mixed $config ): mixed
|
||||
{
|
||||
$key = $this->generateKey( $config );
|
||||
|
||||
if( isset( \IPS\Data\Store::i()->$key ) and \IPS\Data\Store::i()->$key !== 0 )
|
||||
if( isset( Store::i()->$key ) and Store::i()->$key !== 0 )
|
||||
{
|
||||
return \unserialize( base64_decode( \IPS\Data\Store::i()->$key ) );
|
||||
return unserialize( base64_decode( Store::i()->$key ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -101,13 +104,13 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($config)
|
||||
public function remove( mixed $config ): bool
|
||||
{
|
||||
$key = $this->generateKey( $config );
|
||||
|
||||
if( isset( \IPS\Data\Store::i()->$key ) )
|
||||
if( isset( Store::i()->$key ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$key );
|
||||
unset( Store::i()->$key );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -119,22 +122,20 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return void
|
||||
*/
|
||||
public function flush($config)
|
||||
public function flush( mixed $config ) : void
|
||||
{
|
||||
if( !isset( \IPS\Data\Store::i()->htmlpurifier_definitions ) )
|
||||
if( !isset( Store::i()->htmlpurifier_definitions ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->htmlpurifier_definitions = array();
|
||||
Store::i()->htmlpurifier_definitions = array();
|
||||
}
|
||||
|
||||
foreach( \IPS\Data\Store::i()->htmlpurifier_definitions as $key )
|
||||
foreach( Store::i()->htmlpurifier_definitions as $key )
|
||||
{
|
||||
if( isset( \IPS\Data\Store::i()->$key ) )
|
||||
if( isset( Store::i()->$key ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$key );
|
||||
unset( Store::i()->$key );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,8 +144,8 @@ class HtmlPurifierDefinitionCache extends \HTMLPurifier_DefinitionCache
|
||||
* @param mixed $config HTML Purifier configuration
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup($config)
|
||||
public function cleanup( mixed $config ) : void
|
||||
{
|
||||
return $this->flush( $config );
|
||||
$this->flush( $config );
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,15 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use HTMLPurifier_URIFilter;
|
||||
use IPS\Settings;
|
||||
use function defined;
|
||||
use const PHP_URL_HOST;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -21,17 +27,17 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
* An HTMLPurifier image transformation that only allows HTTPS images
|
||||
* @see https://stackoverflow.com/questions/34876151/htmlpurifier-allow-scheme-for-specific-tags
|
||||
*/
|
||||
class _HtmlPurifierHttpsImages extends \HTMLPurifier_URIFilter
|
||||
class HtmlPurifierHttpsImages extends HTMLPurifier_URIFilter
|
||||
{
|
||||
public $name = 'HttpsEmbedScheme';
|
||||
public $ourHost = '';
|
||||
public string $ourHost = '';
|
||||
|
||||
public function prepare( $config )
|
||||
public function prepare( $config ) : void
|
||||
{
|
||||
$this->ourHost = parse_url( \IPS\Settings::i()->base_url, \PHP_URL_HOST );
|
||||
$this->ourHost = parse_url( Settings::i()->base_url, PHP_URL_HOST );
|
||||
}
|
||||
|
||||
public function filter( &$uri, $config, $context )
|
||||
public function filter( &$uri, $config, $context ): bool
|
||||
{
|
||||
/* We only care about embedded resources for this, skip src attr so our own parser can handle that. */
|
||||
if ( !$context->get( 'EmbeddedURI', true ) OR $context->get( 'CurrentAttr', true ) == 'src' )
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief A HTMLPurifier Attribute Definition used for attributes which must be internal URLs or Integers (such as data-fileid for attachments)
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 21 October 2024
|
||||
*/
|
||||
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A HTMLPurifier Attribute Definition used for attributes which must be internal URLs or Integers (such as data-fileid for attachments)
|
||||
*/
|
||||
class _HtmlPurifierIntOrInternalLink extends HtmlPurifierInternalLinkDef
|
||||
{
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @param string $value
|
||||
* @param \HTMLPurifier_Config $config
|
||||
* @param \HTMLPurifier_Context $context
|
||||
* @return bool|string
|
||||
*/
|
||||
public function validate( $value, $config, $context )
|
||||
{
|
||||
$parentCheck = parent::validate( $value, $config, $context );
|
||||
|
||||
if( $parentCheck !== FALSE )
|
||||
{
|
||||
return $parentCheck;
|
||||
}
|
||||
|
||||
$integer = new \HTMLPurifier_AttrDef_Integer( false );
|
||||
return $integer->validate( $value, $config, $context );
|
||||
}
|
||||
}
|
||||
@@ -11,29 +11,40 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use HTMLPurifier_AttrDef_URI;
|
||||
use HTMLPurifier_Config;
|
||||
use HTMLPurifier_Context;
|
||||
use IPS\File;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Http\Url\Friendly;
|
||||
use IPS\Http\Url\Internal;
|
||||
use IPS\Settings;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A HTMLPurifier Attribute Definition used for attributes which must be internal URLs
|
||||
*/
|
||||
class _HtmlPurifierInternalLinkDef extends \HTMLPurifier_AttrDef_URI
|
||||
class HtmlPurifierInternalLinkDef extends HTMLPurifier_AttrDef_URI
|
||||
{
|
||||
/**
|
||||
* @brief Allowed bases
|
||||
*/
|
||||
protected $allowedBases = NULL;
|
||||
protected ?array $allowedBases = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param bool $embeds_resource Does the URI here result in an extra HTTP request?
|
||||
* @param array|null $allowedBases If an array is provided, only URLs with the query strings set allowed - for example array( array( 'app' => 'core', 'module' => 'members', 'controller' => 'profile' ) ) will only allow URLs to profiles. If NULL, any internal URL beside the open proxy and attachment downloads is allowed
|
||||
* @param array|null $allowedBases If an array is provided, only URLs with the query strings set allowed - for example array( array( 'app' => 'core', 'module' => 'members', 'controller' => 'profile' ) ) will only allow URLs to profiles. If NULL, any internal URL beside the open proxy and attachment downloads is allowed
|
||||
*/
|
||||
public function __construct( $embeds_resource = false, $allowedBases = NULL )
|
||||
public function __construct( bool $embeds_resource=FALSE, array $allowedBases = NULL )
|
||||
{
|
||||
$this->allowedBases = $allowedBases;
|
||||
return parent::__construct( $embeds_resource );
|
||||
@@ -43,24 +54,17 @@ class _HtmlPurifierInternalLinkDef extends \HTMLPurifier_AttrDef_URI
|
||||
* Validate
|
||||
*
|
||||
* @param string $uri
|
||||
* @param \HTMLPurifier_Config $config
|
||||
* @param \HTMLPurifier_Context $context
|
||||
* @param HTMLPurifier_Config $config
|
||||
* @param HTMLPurifier_Context $context
|
||||
* @return bool|string
|
||||
*/
|
||||
public function validate($uri, $config, $context)
|
||||
{
|
||||
public function validate($uri, $config, $context): bool|string
|
||||
{
|
||||
/* Create the URL */
|
||||
try
|
||||
{
|
||||
$url = \IPS\Http\Url::createFromString( str_replace( array( '%7B___base_url___%7D/', '{___base_url___}/' ), \IPS\Settings::i()->base_url, $uri ) );
|
||||
}
|
||||
catch( \IPS\Http\Url\Exception $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
$url = Url::createFromString( str_replace( array( '%7B___base_url___%7D/', '{___base_url___}/' ), Settings::i()->base_url, $uri ) );
|
||||
|
||||
/* If it's not internal, we can stop now */
|
||||
if ( !( $url instanceof \IPS\Http\Url\Internal ) )
|
||||
if ( !( $url instanceof Internal ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -69,7 +73,7 @@ class _HtmlPurifierInternalLinkDef extends \HTMLPurifier_AttrDef_URI
|
||||
if ( $this->allowedBases )
|
||||
{
|
||||
$isOkay = FALSE;
|
||||
$queryString = ( $url instanceof \IPS\Http\Url\Friendly ) ? ( $url->hiddenQueryString + $url->queryString ) : $url->queryString;
|
||||
$queryString = ( $url instanceof Friendly ) ? ( $url->hiddenQueryString + $url->queryString ) : $url->queryString;
|
||||
|
||||
foreach ( $this->allowedBases as $requiredQueryString )
|
||||
{
|
||||
@@ -117,15 +121,15 @@ class _HtmlPurifierInternalLinkDef extends \HTMLPurifier_AttrDef_URI
|
||||
/**
|
||||
* @brief Uploaded file base URLs (i.e. URL to uploads directory)
|
||||
*/
|
||||
protected static $uploadUrls = NULL;
|
||||
protected static ?array $uploadUrls = NULL;
|
||||
|
||||
/**
|
||||
* Fetch and cache upload URLs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function getUploadUrls()
|
||||
{
|
||||
/**
|
||||
* Fetch and cache upload URLs
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected static function getUploadUrls(): ?array
|
||||
{
|
||||
if( static::$uploadUrls !== NULL )
|
||||
{
|
||||
return static::$uploadUrls;
|
||||
@@ -133,15 +137,15 @@ class _HtmlPurifierInternalLinkDef extends \HTMLPurifier_AttrDef_URI
|
||||
|
||||
static::$uploadUrls = array();
|
||||
|
||||
foreach( \IPS\File::getStore() as $configuration )
|
||||
foreach( File::getStore() as $configuration )
|
||||
{
|
||||
$class = \IPS\File::getClass( $configuration['id'] );
|
||||
$class = File::getClass( $configuration['id'] );
|
||||
|
||||
if( $class->baseUrl() !== NULL )
|
||||
{
|
||||
$url = new \IPS\Http\Url( $class->baseUrl() );
|
||||
$url = new Url( $class->baseUrl() );
|
||||
|
||||
if( $url instanceof \IPS\Http\Url\Internal )
|
||||
if( $url instanceof Internal )
|
||||
{
|
||||
static::$uploadUrls[ $class->baseUrl() ] = $class->baseUrl();
|
||||
}
|
||||
|
||||
@@ -11,27 +11,34 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use HTMLPurifier_AttrDef_URI;
|
||||
use HTMLPurifier_Config;
|
||||
use HTMLPurifier_Context;
|
||||
use function count;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A HTMLPurifier Attribute Definition used for attributes which must be internal URLs
|
||||
*/
|
||||
class _HtmlPurifierSrcsetDef extends \HTMLPurifier_AttrDef_URI
|
||||
class HtmlPurifierSrcsetDef extends HTMLPurifier_AttrDef_URI
|
||||
{
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @param string $srcset
|
||||
* @param \HTMLPurifier_Config $config
|
||||
* @param \HTMLPurifier_Context $context
|
||||
* @param HTMLPurifier_Config $config
|
||||
* @param HTMLPurifier_Context $context
|
||||
* @return bool|string
|
||||
*/
|
||||
public function validate($srcset, $config, $context)
|
||||
{
|
||||
public function validate($srcset, $config, $context): bool|string
|
||||
{
|
||||
$return = array();
|
||||
|
||||
foreach ( explode( ',', $srcset ) as $src )
|
||||
@@ -47,7 +54,7 @@ class _HtmlPurifierSrcsetDef extends \HTMLPurifier_AttrDef_URI
|
||||
}
|
||||
}
|
||||
|
||||
if ( \count( $return ) )
|
||||
if ( count( $return ) )
|
||||
{
|
||||
return implode( ', ', $return );
|
||||
}
|
||||
|
||||
@@ -11,36 +11,44 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use HTMLPurifier_AttrDef;
|
||||
use HTMLPurifier_AttrDef_Switch;
|
||||
use HTMLPurifier_Config;
|
||||
use HTMLPurifier_Context;
|
||||
use function count;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A HTMLPurifier Attribute Definition which imitates HTMLPurifier_AttrDef_Switch but allows checking if certain attributes exist
|
||||
*/
|
||||
class _HtmlPurifierSwitchAttrDef extends \HTMLPurifier_AttrDef_Switch
|
||||
class HtmlPurifierSwitchAttrDef extends HTMLPurifier_AttrDef_Switch
|
||||
{
|
||||
/**
|
||||
* @brief Is the attribute required
|
||||
*/
|
||||
public $required = FALSE;
|
||||
public bool $required = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Attributes
|
||||
*/
|
||||
protected $attributes = array();
|
||||
protected array $attributes = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $tag The tag name to check
|
||||
* @param array $attributes The attributes to check on
|
||||
* @param \HTMLPurifier_AttrDef $with_tag If $tag matches and all $attributes are present, this definition will be used
|
||||
* @param \HTMLPurifier_AttrDef $without_tag Otherwise, this definition will be used
|
||||
* @param HTMLPurifier_AttrDef $with_tag If $tag matches and all $attributes are present, this definition will be used
|
||||
* @param HTMLPurifier_AttrDef $without_tag Otherwise, this definition will be used
|
||||
*/
|
||||
public function __construct( $tag, $attributes, $with_tag, $without_tag )
|
||||
public function __construct( string $tag, array $attributes, $with_tag, HTMLPurifier_AttrDef $without_tag )
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
parent::__construct( $tag, $with_tag, $without_tag );
|
||||
@@ -50,15 +58,15 @@ class _HtmlPurifierSwitchAttrDef extends \HTMLPurifier_AttrDef_Switch
|
||||
* Validate
|
||||
*
|
||||
* @param string $string
|
||||
* @param \HTMLPurifier_Config $config
|
||||
* @param \HTMLPurifier_Context $context
|
||||
* @param HTMLPurifier_Config $config
|
||||
* @param HTMLPurifier_Context $context
|
||||
* @return bool|string
|
||||
*/
|
||||
public function validate( $string, $config, $context )
|
||||
{
|
||||
public function validate( $string, $config, $context ): bool|string
|
||||
{
|
||||
$token = $context->get('CurrentToken', true);
|
||||
|
||||
if ( \count( array_diff( $this->attributes, array_keys( $token->attr ) ) ) )
|
||||
if ( count( array_diff( $this->attributes, array_keys( $token->attr ) ) ) )
|
||||
{
|
||||
return $this->withoutTag->validate( $string, $config, $context );
|
||||
}
|
||||
|
||||
+145
-121
@@ -11,72 +11,96 @@
|
||||
namespace IPS\Text;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\Application;
|
||||
use IPS\Db;
|
||||
use IPS\File;
|
||||
use IPS\gallery\Album;
|
||||
use IPS\gallery\Image;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Output;
|
||||
use IPS\Settings;
|
||||
use IPS\Theme;
|
||||
use UnderflowException;
|
||||
use UnexpectedValueException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function str_ireplace;
|
||||
use function str_replace;
|
||||
use function stristr;
|
||||
use function strstr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy Text Parser
|
||||
*/
|
||||
class _LegacyParser
|
||||
class LegacyParser
|
||||
{
|
||||
/**
|
||||
* @brief Maximum number of embeds we will try.
|
||||
* @note Attempting to pull too many during the rebuild process can easily time out
|
||||
*/
|
||||
public $maxEmbeds = 10;
|
||||
public int $maxEmbeds = 10;
|
||||
|
||||
/**
|
||||
* Parse statically
|
||||
*
|
||||
* @param string $value The value to parse
|
||||
* @param \IPS\Member|null $member The member posting. NULL will use currently logged in member.
|
||||
* @param bool $allowHtml Allow HTML
|
||||
* @param string $attachClass Key to use for attachments
|
||||
* @param int $id1 ID1 to use for attachments
|
||||
* @param int $id2 ID2 to use for attachments
|
||||
* @param int|NULL $id3 ID3 to use for attachments
|
||||
* @param string $itemClass The *item* classname (e.g. IPS\forums\Topic)
|
||||
* @param string $value The value to parse
|
||||
* @param Member|null $member The member posting. NULL will use currently logged in member.
|
||||
* @param bool $allowHtml Allow HTML
|
||||
* @param string|null $attachClass Key to use for attachments
|
||||
* @param int $id1 ID1 to use for attachments
|
||||
* @param int $id2 ID2 to use for attachments
|
||||
* @param int|null $id3 ID3 to use for attachments
|
||||
* @param string|null $itemClass The *item* classname (e.g. IPS\forums\Topic)
|
||||
* @return string
|
||||
* @see __construct
|
||||
*/
|
||||
public static function parseStatic( $value, $member=NULL, $allowHtml=FALSE, $attachClass=null, $id1=0, $id2=0, $id3=NULL, $itemClass=NULL )
|
||||
public static function parseStatic(string $value, Member $member=NULL, bool $allowHtml=FALSE, string $attachClass=null, int $id1=0, int $id2=0, int $id3=NULL, string $itemClass=NULL ): string
|
||||
{
|
||||
$obj = new static( $member, $allowHtml, $attachClass, $id1, $id2, $id3, $itemClass );
|
||||
$obj = new static($member, $allowHtml, $attachClass, $id1, $id2, $id3, $itemClass);
|
||||
return $obj->parse( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief BBcodes
|
||||
*/
|
||||
public $bbcodes = NULL;
|
||||
public static ?array $bbcodes = NULL;
|
||||
|
||||
/**
|
||||
* @brief Emoticons
|
||||
*/
|
||||
public $emoticons = NULL;
|
||||
public ?array $emoticons = NULL;
|
||||
|
||||
/**
|
||||
* Can use plugin?
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $bbcode BBCode
|
||||
* @param Member $member The member
|
||||
* @param string $bbcode BBCode
|
||||
* @return bool
|
||||
*/
|
||||
public static function canUse( \IPS\Member $member, $bbcode )
|
||||
public static function canUse(Member $member, string $bbcode ): bool
|
||||
{
|
||||
foreach( static::$bbcodes as $code )
|
||||
{
|
||||
if( $code['bbcode_tag'] == $bbcode OR ( $code['bbcode_aliases'] AND \in_array( $bbcode, explode( ',', $code['bbcode_aliases'] ) ) ) )
|
||||
if( $code['bbcode_tag'] == $bbcode OR ( $code['bbcode_aliases'] AND in_array( $bbcode, explode( ',', $code['bbcode_aliases'] ) ) ) )
|
||||
{
|
||||
if( $code['bbcode_groups'] == 'all' )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( $member->inGroup( explode( ',', $bbcode['bbcode_groups'] ) ) )
|
||||
if( $member->inGroup( explode( ',', $code['bbcode_groups'] ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -89,64 +113,64 @@ class _LegacyParser
|
||||
/**
|
||||
* @brief Member
|
||||
*/
|
||||
protected $member = NULL;
|
||||
protected ?Member $member = NULL;
|
||||
|
||||
/**
|
||||
* @brief Allow HTML
|
||||
*/
|
||||
protected $allowHtml = FALSE;
|
||||
protected bool $allowHtml = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Parser object
|
||||
*/
|
||||
public $parser = NULL;
|
||||
public mixed $parser = NULL;
|
||||
|
||||
/**
|
||||
* @brief Key for attachments
|
||||
*/
|
||||
protected $attachClass = NULL;
|
||||
protected ?string $attachClass = NULL;
|
||||
|
||||
/**
|
||||
* @brief Item classname
|
||||
*/
|
||||
protected $itemClass = NULL;
|
||||
protected ?string $itemClass = NULL;
|
||||
|
||||
/**
|
||||
* @brief ID1 to use for attachments
|
||||
*/
|
||||
protected $idOne = 0;
|
||||
protected int $idOne = 0;
|
||||
|
||||
/**
|
||||
* @brief ID2 to use for attachments
|
||||
*/
|
||||
protected $idTwo = 0;
|
||||
protected int $idTwo = 0;
|
||||
|
||||
/**
|
||||
* @brief ID3 to use for attachments
|
||||
*/
|
||||
protected $idThree = 0;
|
||||
protected ?int $idThree = 0;
|
||||
|
||||
/**
|
||||
* @brief Are Acronyms Supported?
|
||||
*/
|
||||
protected static $_newAcronyms = null;
|
||||
protected static ?bool $_newAcronyms = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\Member|null $member The member posting. NULL will use guest.
|
||||
* @param bool $allowHtml Allow HTML
|
||||
* @param string $attachClass Key to use for attachments
|
||||
* @param int $id1 ID1 to use for attachments
|
||||
* @param int $id2 ID2 to use for attachments
|
||||
* @param int|NULL $id3 ID3 to use for attachments
|
||||
* @param string $itemClass The *item* classname (e.g. IPS\forums\Topic)
|
||||
* @param Member|null $member The member posting. NULL will use guest.
|
||||
* @param bool $allowHtml Allow HTML
|
||||
* @param string|null $attachClass Key to use for attachments
|
||||
* @param int $id1 ID1 to use for attachments
|
||||
* @param int $id2 ID2 to use for attachments
|
||||
* @param int|null $id3 ID3 to use for attachments
|
||||
* @param string|null $itemClass The *item* classname (e.g. IPS\forums\Topic)
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $member=NULL, $allowHtml=FALSE, $attachClass=null, $id1=0, $id2=0, $id3=NULL, $itemClass=NULL )
|
||||
public function __construct( Member $member=NULL, bool $allowHtml=FALSE, string $attachClass=null, int $id1=0, int $id2=0, int $id3=NULL, string $itemClass=NULL )
|
||||
{
|
||||
/* Get member */
|
||||
$this->member = $member === NULL ? \IPS\Member::load(0) : $member;
|
||||
$this->member = $member === NULL ? Member::load(0) : $member;
|
||||
|
||||
/* Remember if we allow HTML */
|
||||
$this->allowHtml = $allowHtml;
|
||||
@@ -163,9 +187,9 @@ class _LegacyParser
|
||||
/* Grab legacy custom bbcodes */
|
||||
try
|
||||
{
|
||||
$this->bbcodes = iterator_to_array( \IPS\Db::i()->select( '*', 'custom_bbcode' )->setKeyField( 'bbcode_tag' ) );
|
||||
$this->bbcodes = iterator_to_array( Db::i()->select( '*', 'custom_bbcode' )->setKeyField( 'bbcode_tag' ) );
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
catch(Db\Exception $e )
|
||||
{
|
||||
$this->bbcodes = array();
|
||||
}
|
||||
@@ -173,9 +197,9 @@ class _LegacyParser
|
||||
/* Grab emoticons */
|
||||
try
|
||||
{
|
||||
$this->emoticons = iterator_to_array( \IPS\Db::i()->select( '*', 'core_emoticons' )->setKeyField( 'typed' ) );
|
||||
$this->emoticons = iterator_to_array( Db::i()->select( '*', 'core_emoticons' )->setKeyField( 'typed' ) );
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
catch(Db\Exception $e )
|
||||
{
|
||||
$this->emoticons = array();
|
||||
}
|
||||
@@ -183,20 +207,20 @@ class _LegacyParser
|
||||
/* The `a_type` column is added in 4.5, so we need to account for this if running the legacy parser during an older upgrade */
|
||||
if( static::$_newAcronyms === NULL )
|
||||
{
|
||||
static::$_newAcronyms = \IPS\Db::i()->checkForColumn( 'core_acronyms', 'a_type' );
|
||||
static::$_newAcronyms = Db::i()->checkForColumn( 'core_acronyms', 'a_type' );
|
||||
}
|
||||
|
||||
/* Grab a new parser object */
|
||||
\IPS\Text\Parser::$requestTimeout = 1;
|
||||
$this->parser = new \IPS\Text\Parser( TRUE, $this->idOne ? array( $this->idOne, $this->idTwo, $this->idThree ) : NULL, $this->member, $this->attachClass, TRUE, ( $this->allowHtml ? FALSE : TRUE ), NULL, static::$_newAcronyms );
|
||||
Parser::$requestTimeout = 1;
|
||||
$this->parser = new ConverterParser( TRUE, $this->idOne ? array( $this->idOne, $this->idTwo, $this->idThree ) : NULL, $this->member, $this->attachClass, TRUE, ( $this->allowHtml ? FALSE : TRUE ), NULL, static::$_newAcronyms );
|
||||
|
||||
/* If we're in the upgrader and the new acronym support hasn't been added yet, populate acronyms manually */
|
||||
if( !static::$_newAcronyms )
|
||||
{
|
||||
$this->parser->caseSensitiveAcronyms = iterator_to_array( \IPS\Db::i()->select( array( 'a_short', 'a_long', "'acronym' as `a_type`" ), 'core_acronyms', array( 'a_casesensitive=1' ) )->setKeyField( 'a_short' ) );
|
||||
$this->parser->caseSensitiveAcronyms = iterator_to_array( Db::i()->select( array( 'a_short', 'a_long', "'acronym' as `a_type`" ), 'core_acronyms', array( 'a_casesensitive=1' ) )->setKeyField( 'a_short' ) );
|
||||
|
||||
$this->parser->caseInsensitiveAcronyms = array();
|
||||
foreach ( \IPS\Db::i()->select( array( 'a_short', 'a_long', "'acronym' as `a_type`" ), 'core_acronyms', array( 'a_casesensitive=0' ) )->setKeyField( 'a_short' ) as $k => $v )
|
||||
foreach ( Db::i()->select( array( 'a_short', 'a_long', "'acronym' as `a_type`" ), 'core_acronyms', array( 'a_casesensitive=0' ) )->setKeyField( 'a_short' ) as $k => $v )
|
||||
{
|
||||
$this->parser->caseInsensitiveAcronyms[ mb_strtolower( $k ) ] = $v;
|
||||
}
|
||||
@@ -219,37 +243,37 @@ class _LegacyParser
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* @param string $value Text to parse
|
||||
* @param string $value Text to parse
|
||||
* @return string
|
||||
*/
|
||||
public function parse( $value )
|
||||
public function parse( string $value ): string
|
||||
{
|
||||
/* We have to fix up newlines a little bit */
|
||||
$codeBlocks = array();
|
||||
$value = str_replace( array( "\r\n", "\r" ), "\n", $value );
|
||||
|
||||
if ( ! \strstr( $value, "\n" ) && ( \stristr( $value, '<br>' ) || \stristr( $value, '<br />' ) ) )
|
||||
if ( ! strstr( $value, "\n" ) && ( stristr( $value, '<br>' ) || stristr( $value, '<br />' ) ) )
|
||||
{
|
||||
$value = \str_ireplace( array( '<br>', '<br />' ), "\n", $value );
|
||||
$value = str_ireplace( array( '<br>', '<br />' ), "\n", $value );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( \stristr( $value, '<br>' ) || \stristr( $value, '<br />' ) || \stristr( $value, '<p>' ) )
|
||||
if ( stristr( $value, '<br>' ) || stristr( $value, '<br />' ) || stristr( $value, '<p>' ) )
|
||||
{
|
||||
/* Protect code tags first... */
|
||||
$value = preg_replace_callback( "/\[(?:code|codebox|sql|php|xml|html).*?\](.+?)\[\/(?:code|codebox|sql|php|xml|html)\]/ims", function( $match ) use ( &$codeBlocks ) {
|
||||
$hash = md5( $match[0] . mt_rand() );
|
||||
$codeBlocks[ $hash ] = ( \stristr( $match[0], '<br>' ) || \stristr( $match[0], '<br />' ) || \stristr( $match[0], '<p>' ) ) ? \str_replace( "\n", "", $match[0] ) : $match[0];
|
||||
$codeBlocks[ $hash ] = ( stristr( $match[0], '<br>' ) || stristr( $match[0], '<br />' ) || stristr( $match[0], '<p>' ) ) ? str_replace( "\n", "", $match[0] ) : $match[0];
|
||||
return $hash;
|
||||
}, $value );
|
||||
|
||||
$value = preg_replace_callback( "/\<pre\s+?class=[\"']_prettyXprint(?:.*?)[\"']\>(.+?)\<\/pre\>/ims", function( $match ) use ( &$codeBlocks ) {
|
||||
$hash = md5( $match[0] . mt_rand() );
|
||||
$codeBlocks[ $hash ] = ( \stristr( $match[0], '<br>' ) || \stristr( $match[0], '<br />' ) || \stristr( $match[0], '<p>' ) ) ? \str_replace( "\n", "", $match[0] ) : $match[0];
|
||||
$codeBlocks[ $hash ] = ( stristr( $match[0], '<br>' ) || stristr( $match[0], '<br />' ) || stristr( $match[0], '<p>' ) ) ? str_replace( "\n", "", $match[0] ) : $match[0];
|
||||
return $hash;
|
||||
}, $value );
|
||||
|
||||
$value = \str_replace( "\n", "", $value );
|
||||
$value = str_replace( "\n", "", $value );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +291,7 @@ class _LegacyParser
|
||||
/* If we had any code blocks, put them back now */
|
||||
foreach( $codeBlocks as $hash => $code )
|
||||
{
|
||||
$value = \str_replace( $hash, $code, $value );
|
||||
$value = str_replace( $hash, $code, $value );
|
||||
}
|
||||
|
||||
/* In case the content rebuild has ran or partially ran on this content... */
|
||||
@@ -281,7 +305,7 @@ class _LegacyParser
|
||||
|
||||
preg_match_all( "#(<img(?:[^>]+?)class=['\"]bbc_emoticon[\"'](?:[^>]+?)alt=['\"](.+?)[\"'](?:[^>]+?)?>)#is", $value, $matches );
|
||||
|
||||
if( \is_array($matches[1]) AND \count($matches[1]) )
|
||||
if( is_array($matches[1]) AND count($matches[1]) )
|
||||
{
|
||||
foreach( $matches[1] as $index => $match )
|
||||
{
|
||||
@@ -303,14 +327,14 @@ class _LegacyParser
|
||||
{
|
||||
$code = str_replace( '<', '<', str_replace( '>', '>', $emoticon['typed'] ) );
|
||||
|
||||
if( !$code or !\stristr( $value, $code ) )
|
||||
if( !$code or !stristr( $value, $code ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! \IPS\File::isFullyQualifiedUrl( $emoticon['image'] ) )
|
||||
if ( ! File::isFullyQualifiedUrl( $emoticon['image'] ) )
|
||||
{
|
||||
$emoticon['image'] = \IPS\File::getClass('core_Emoticons')->baseUrl() . '/' . $emoticon['image'];
|
||||
$emoticon['image'] = File::getClass('core_Emoticons')->baseUrl() . '/' . $emoticon['image'];
|
||||
}
|
||||
|
||||
$quotedCode = preg_quote( $code, '/' );
|
||||
@@ -349,7 +373,7 @@ class _LegacyParser
|
||||
|
||||
foreach( $matches[0] as $k => $m )
|
||||
{
|
||||
$c = \count( $codeboxes );
|
||||
$c = count( $codeboxes );
|
||||
$codeboxes[ $c ] = $m;
|
||||
|
||||
$replacement = '<!--codeboxes{' . $c . '}-->';
|
||||
@@ -361,7 +385,7 @@ class _LegacyParser
|
||||
|
||||
foreach( $matches[0] as $k => $m )
|
||||
{
|
||||
$c = \count( $codeboxes );
|
||||
$c = count( $codeboxes );
|
||||
$codeboxes[ $c ] = $m;
|
||||
|
||||
$replacement = '<!--codeboxes{' . $c . '}-->';
|
||||
@@ -374,8 +398,8 @@ class _LegacyParser
|
||||
$tables = array();
|
||||
foreach( $matches[0] as $k => $m )
|
||||
{
|
||||
$c = \count( $tables );
|
||||
$tables[ $c ] = \str_ireplace( '<td><br />', '<td>', $m ); // Fix up un-needed BRs added earlier in this method
|
||||
$c = count( $tables );
|
||||
$tables[ $c ] = str_ireplace( '<td><br />', '<td>', $m ); // Fix up un-needed BRs added earlier in this method
|
||||
|
||||
$replacement = '<!--tables{' . $c . '}-->';
|
||||
|
||||
@@ -432,7 +456,7 @@ class _LegacyParser
|
||||
$value = str_replace( "[/quote]", "</div></blockquote>", $value );
|
||||
|
||||
/* Fix download manager embedded screenshot URLs */
|
||||
$value = preg_replace_callback( "#<img src=['\"]" . preg_quote( rtrim( \IPS\Settings::i()->base_url, '/' ), '#' ) . "/index\.php\?app=downloads(?:&|&)module=display(?:&|&)section=screenshot(?:&|&)id=(\d+?)['\"]([^>]*?)>#si", array( $this, '_fixDownloadsScreenshots' ), $value );
|
||||
$value = preg_replace_callback( "#<img src=['\"]" . preg_quote( rtrim( Settings::i()->base_url, '/' ), '#' ) . "/index\.php\?app=downloads(?:&|&)module=display(?:&|&)section=screenshot(?:&|&)id=(\d+?)['\"]([^>]*?)>#si", array( $this, '_fixDownloadsScreenshots' ), $value );
|
||||
|
||||
/* These were auto-replacements previously */
|
||||
$value = str_ireplace( "(c)" , "©" , $value );
|
||||
@@ -457,7 +481,7 @@ class _LegacyParser
|
||||
}
|
||||
|
||||
/* Convert bbcode tags, but only those our new parser doesn't handle */
|
||||
foreach( $this->bbcodes as $code )
|
||||
foreach( $this->parser->bbcodes as $code )
|
||||
{
|
||||
/* If we don't have a regex replacement, probably because we used to use a plugin, we can't do this automatically */
|
||||
if( !$code['bbcode_replace'] )
|
||||
@@ -520,7 +544,7 @@ class _LegacyParser
|
||||
|
||||
preg_match_all( "/\[attachment=(.+?):(.+?)\]/ims", $value, $matches );
|
||||
|
||||
if( \count( $matches[1] ) )
|
||||
if( count( $matches[1] ) )
|
||||
{
|
||||
foreach( $matches[1] as $id )
|
||||
{
|
||||
@@ -535,11 +559,11 @@ class _LegacyParser
|
||||
$where[] = array( 'id2=?', $this->idTwo );
|
||||
}
|
||||
|
||||
$mappedAttachments = iterator_to_array( \IPS\Db::i()->select( '*', 'core_attachments_map', $where )->setKeyField( 'attachment_id' ) );
|
||||
$mappedAttachments = iterator_to_array( Db::i()->select( '*', 'core_attachments_map', $where )->setKeyField( 'attachment_id' ) );
|
||||
|
||||
foreach( $mappedAttachments as $attachmentId => $map )
|
||||
{
|
||||
if( !\in_array( $attachmentId, $embeddedAttachments ) )
|
||||
if( !in_array( $attachmentId, $embeddedAttachments ) )
|
||||
{
|
||||
$value .= '<p>[attachment=' . $attachmentId . ':name]</p>';
|
||||
}
|
||||
@@ -554,11 +578,11 @@ class _LegacyParser
|
||||
case 'calendar':
|
||||
try
|
||||
{
|
||||
$event = \IPS\Db::i()->select( '*', 'calendar_events', array( 'event_id=?', (int) $matches[3] ) )->first();
|
||||
$url = \IPS\Http\Url::internal( "app=calendar&module=events&controller=event&id={$event['event_id']}", 'front', 'calendar_event', $event['event_title_seo'] );
|
||||
$event = Db::i()->select( '*', 'calendar_events', array( 'event_id=?', (int) $matches[3] ) )->first();
|
||||
$url = Url::internal( "app=calendar&module=events&controller=event&id={$event['event_id']}", 'front', 'calendar_event', $event['event_title_seo'] );
|
||||
return "<p><a href='{$url}'>{$url}</a></p>";
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -566,7 +590,7 @@ class _LegacyParser
|
||||
|
||||
case 'gallery':
|
||||
/* Make sure gallery is enabled first */
|
||||
if ( \IPS\Application::appIsEnabled( 'gallery' ) === FALSE )
|
||||
if ( Application::appIsEnabled( 'gallery' ) === FALSE )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -575,10 +599,10 @@ class _LegacyParser
|
||||
{
|
||||
try
|
||||
{
|
||||
$image = \IPS\gallery\Image::constructFromData( \IPS\Db::i()->select( '*', 'gallery_images', array( 'image_id=?', (int) $matches[3] ) )->first() );
|
||||
$image = Image::constructFromData( Db::i()->select( '*', 'gallery_images', array( 'image_id=?', (int) $matches[3] ) )->first() );
|
||||
return "<p><a href='{$image->url()}'><img src='{$image->embedImage()->url}' alt='{$image->caption}'></a></p>";
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -587,10 +611,10 @@ class _LegacyParser
|
||||
{
|
||||
try
|
||||
{
|
||||
$album = \IPS\gallery\Album::constructFromData( \IPS\Db::i()->select( '*', 'gallery_albums', array( 'album_id=?', (int) $matches[3] ) )->first() );
|
||||
return \IPS\Text\Parser::embeddableMedia( \IPS\Http\Url::createFromString( $album->url(), TRUE, TRUE ), FALSE, $this->member );
|
||||
$album = Album::constructFromData( Db::i()->select( '*', 'gallery_albums', array( 'album_id=?', (int) $matches[3] ) )->first() );
|
||||
return Parser::embeddableMedia( Url::createFromString( $album->url(), TRUE, TRUE ), FALSE, $this->member );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -600,11 +624,11 @@ class _LegacyParser
|
||||
case 'downloads':
|
||||
try
|
||||
{
|
||||
$file = \IPS\Db::i()->select( '*', 'downloads_files', array( 'file_id=?', (int) $matches[3] ) )->first();
|
||||
$url = \IPS\Http\Url::internal( "app=downloads&module=downloads&controller=view&id={$file['file_id']}", 'front', 'downloads_file', $file['file_name_furl'] );
|
||||
$file = Db::i()->select( '*', 'downloads_files', array( 'file_id=?', (int) $matches[3] ) )->first();
|
||||
$url = Url::internal( "app=downloads&module=downloads&controller=view&id={$file['file_id']}", 'front', 'downloads_file', $file['file_name_furl'] );
|
||||
return "<p><a href='{$url}'>{$url}</a></p>";
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -618,11 +642,11 @@ class _LegacyParser
|
||||
case 'blog':
|
||||
try
|
||||
{
|
||||
$entry = \IPS\Db::i()->select( '*', 'blog_entries', array( 'entry_id=?', (int) $matches[3] ) )->first();
|
||||
$url = \IPS\Http\Url::internal( "app=blog&module=blogs&controller=entry&id={$entry['entry_id']}", 'front', 'blog_entry', $entry['entry_name_seo'] );
|
||||
$entry = Db::i()->select( '*', 'blog_entries', array( 'entry_id=?', (int) $matches[3] ) )->first();
|
||||
$url = Url::internal( "app=blog&module=blogs&controller=entry&id={$entry['entry_id']}", 'front', 'blog_entry', $entry['entry_name_seo'] );
|
||||
return "<p><a href='{$url}'>{$url}</a></p>";
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@@ -742,7 +766,7 @@ class _LegacyParser
|
||||
$url = preg_replace( "/#entry(\d+)/", $sep . "do=findComment&comment=$1", $url );
|
||||
}
|
||||
|
||||
$c = \count( $urls );
|
||||
$c = count( $urls );
|
||||
$urls[ $c ] = str_replace( $matches[1][ $k ], $url, $m );
|
||||
|
||||
$replacement = '<!--url{' . $c . '}-->';
|
||||
@@ -750,12 +774,12 @@ class _LegacyParser
|
||||
try
|
||||
{
|
||||
/* In 3.x, hyperlinked YouTube URLs did replace as long as a data attribute wasn't present */
|
||||
if( ! mb_strpos( $matches[1][ $k ], \IPS\Settings::i()->base_url ) AND ( mb_strpos( $matches[0][ $k ], 'youtube.co' ) OR mb_strpos( $matches[0][ $k ], 'youtu.be' ) ) and ! mb_strpos( $matches[0][ $k ], 'nomediaparse' ) AND $response = \IPS\Text\Parser::embeddableMedia( \IPS\Http\Url::createFromString( $matches[1][ $k ], FALSE, TRUE ), FALSE, $this->member ) )
|
||||
if( ! mb_strpos( $matches[1][ $k ], Settings::i()->base_url ) AND ( mb_strpos( $matches[0][ $k ], 'youtube.co' ) OR mb_strpos( $matches[0][ $k ], 'youtu.be' ) ) and ! mb_strpos( $matches[0][ $k ], 'nomediaparse' ) AND $response = Parser::embeddableMedia( Url::createFromString( $matches[1][ $k ], FALSE, TRUE ), FALSE, $this->member ) )
|
||||
{
|
||||
$urls[ $c ] = $response;
|
||||
}
|
||||
}
|
||||
catch( \UnexpectedValueException $e ){}
|
||||
catch( UnexpectedValueException $e ){}
|
||||
|
||||
$value = str_replace( $m, $replacement, $value );
|
||||
}
|
||||
@@ -765,7 +789,7 @@ class _LegacyParser
|
||||
|
||||
foreach( $matches[0] as $m )
|
||||
{
|
||||
$c = \count( $urls );
|
||||
$c = count( $urls );
|
||||
$urls[ $c ] = $m;
|
||||
|
||||
$value = str_replace( $m, '<!--url{' . $c . '}-->', $value );
|
||||
@@ -776,7 +800,7 @@ class _LegacyParser
|
||||
|
||||
foreach( $matches[1] as $k => $m )
|
||||
{
|
||||
$c = \count( $urls );
|
||||
$c = count( $urls );
|
||||
$urls[ $c ] = "<a href='{$m}'>{$m}</a>";
|
||||
|
||||
$value = str_replace( $matches[0][ $k ], '<!--url{' . $c . '}-->', $value );
|
||||
@@ -809,9 +833,9 @@ class _LegacyParser
|
||||
|
||||
try
|
||||
{
|
||||
$me = \IPS\Text\Parser::embeddableMedia( \IPS\Http\Url::createFromString( $url, FALSE, TRUE ), FALSE, $this->member );
|
||||
$me = Parser::embeddableMedia( Url::createFromString( $url, FALSE, TRUE ), FALSE, $this->member );
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
catch( Exception $e ){}
|
||||
}
|
||||
|
||||
if( $me )
|
||||
@@ -819,7 +843,7 @@ class _LegacyParser
|
||||
$embedCount++;
|
||||
}
|
||||
|
||||
$c = \count( $urls );
|
||||
$c = count( $urls );
|
||||
$urls[ $c ] = $me ?: "<a href='{$m}'>{$m}</a>";
|
||||
|
||||
$value = str_replace( $matches[1][ $k ], '<!--url{' . $c . '}-->', $value );
|
||||
@@ -836,14 +860,14 @@ class _LegacyParser
|
||||
$value = preg_replace_callback( "/\[attachment=(.+?):(.+?)\]/ims", function( $matches ) {
|
||||
try
|
||||
{
|
||||
$attachment = \IPS\Db::i()->select( '*', 'core_attachments', array( 'attach_id=?', (int) $matches[1] ) )->first();
|
||||
$attachment = Db::i()->select( '*', 'core_attachments', array( 'attach_id=?', (int) $matches[1] ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
catch( UnderflowException $e )
|
||||
{
|
||||
$attachment = array( 'attach_is_image' => 0, 'attach_location' => '' );
|
||||
}
|
||||
|
||||
$url = \IPS\Http\Url::baseUrl( \IPS\Http\Url::PROTOCOL_RELATIVE ) . "applications/core/interface/file/attachment.php?id=" . $attachment['attach_id'];
|
||||
$url = Url::baseUrl( Url::PROTOCOL_RELATIVE ) . "applications/core/interface/file/attachment.php?id=" . $attachment['attach_id'];
|
||||
if ( $attachment['attach_security_key'] )
|
||||
{
|
||||
$url .= "&key={$attachment['attach_security_key']}";
|
||||
@@ -852,15 +876,15 @@ class _LegacyParser
|
||||
if( $attachment['attach_is_image'] )
|
||||
{
|
||||
$attachment['attach_thumb_location'] = $attachment['attach_thumb_location'] ?: $attachment['attach_location'];
|
||||
$return = "<a class='ipsAttachLink ipsAttachLink_image' href='{fileStore.core_Attachment}/{$attachment['attach_location']}'><img src='{fileStore.core_Attachment}/{$attachment['attach_thumb_location']}' data-fileid='" . \IPS\Settings::i()->base_url . "applications/core/interface/file/attachment.php?id={$attachment['attach_id']}' class='ipsImage ipsImage_thumbnailed'></a>";
|
||||
$return = "<a class='ipsAttachLink ipsAttachLink_image' href='{fileStore.core_Attachment}/{$attachment['attach_location']}'><img src='{fileStore.core_Attachment}/{$attachment['attach_thumb_location']}' data-fileid='" . Settings::i()->base_url . "applications/core/interface/file/attachment.php?id={$attachment['attach_id']}' class='ipsImage ipsImage_thumbnailed'></a>";
|
||||
}
|
||||
elseif( \in_array( $attachment['attach_ext'], \IPS\File::$videoExtensions ) )
|
||||
elseif( in_array( $attachment['attach_ext'], File::$videoExtensions ) )
|
||||
{
|
||||
$return = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedVideo( $attachment['attach_location'], $url, $attachment['attach_file'], \IPS\File::getMimeType( $attachment['attach_file'] ), $attachment['attach_id'] );
|
||||
$return = Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedVideo( $attachment['attach_location'], $url, $attachment['attach_file'], File::getMimeType( $attachment['attach_file'] ), $attachment['attach_id'] );
|
||||
}
|
||||
elseif( \in_array( $attachment['attach_ext'], \IPS\File::$audioExtensions ) )
|
||||
elseif( in_array( $attachment['attach_ext'], File::$audioExtensions ) )
|
||||
{
|
||||
$return = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedAudio( $attachment['attach_location'], $url, $attachment['attach_file'], \IPS\File::getMimeType( $attachment['attach_file'] ), $attachment['attach_id'] );
|
||||
$return = Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedAudio( $attachment['attach_location'], $url, $attachment['attach_file'], File::getMimeType( $attachment['attach_file'] ), $attachment['attach_id'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -989,13 +1013,13 @@ class _LegacyParser
|
||||
/* Return */
|
||||
if ( mb_stristr( $value, '<fileStore.' ) )
|
||||
{
|
||||
\IPS\Output::i()->parseFileObjectUrls( $value );
|
||||
Output::i()->parseFileObjectUrls( $value );
|
||||
}
|
||||
|
||||
$result = $this->parser->parse( $value );
|
||||
|
||||
/* If they are not using UTF8MB4, we need to convert emoji back to html entities as HTMLPurifier will have converted them on us */
|
||||
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') !== TRUE )
|
||||
if ( Settings::i()->getFromConfGlobal('sql_utf8mb4') !== TRUE )
|
||||
{
|
||||
$result = preg_replace_callback( '/[\x{10000}-\x{10FFFF}]/u', function( $mb4Character ) {
|
||||
return mb_convert_encoding( $mb4Character[0], 'HTML-ENTITIES', 'UTF-8' );
|
||||
@@ -1011,10 +1035,10 @@ class _LegacyParser
|
||||
/**
|
||||
* Parse new quotes
|
||||
*
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @return string Converted text
|
||||
*/
|
||||
protected function _parseOldQuote( $matches=array() )
|
||||
protected function _parseOldQuote( array $matches=array() ): string
|
||||
{
|
||||
if ( !$matches[1] )
|
||||
{
|
||||
@@ -1033,7 +1057,7 @@ class _LegacyParser
|
||||
|
||||
if ( $match[1] )
|
||||
{
|
||||
$return[] = " post='" . \intval($match[1]) . "'";
|
||||
$return[] = " post='" . intval($match[1]) . "'";
|
||||
}
|
||||
|
||||
if ( $match[2] )
|
||||
@@ -1048,14 +1072,14 @@ class _LegacyParser
|
||||
/**
|
||||
* Parse new quotes #2
|
||||
*
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @return string Converted text
|
||||
*/
|
||||
protected function _parseOldBlockquote( $matches=array() )
|
||||
protected function _parseOldBlockquote( array $matches=array() ): string
|
||||
{
|
||||
$parameters = array( 'data-ipsQuote' => '', 'class' => 'ipsQuote' );
|
||||
|
||||
if( \count( $matches ) )
|
||||
if( count( $matches ) )
|
||||
{
|
||||
preg_match( "/data-author=['\"](.+?)[\"']/i", static::_cleanQuoteName( $matches[1] ), $author );
|
||||
preg_match( "/data-cid=['\"](.+?)[\"']/i", $matches[1], $cid );
|
||||
@@ -1101,14 +1125,14 @@ class _LegacyParser
|
||||
/**
|
||||
* Parse new quotes #3
|
||||
*
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @return string Converted text
|
||||
*/
|
||||
protected function _parseOldQuoteBbcode( $matches=array() )
|
||||
protected function _parseOldQuoteBbcode( array $matches=array() ): string
|
||||
{
|
||||
$parameters = array( 'data-ipsQuote' => '', 'class' => 'ipsQuote' );
|
||||
|
||||
if( \count( $matches ) )
|
||||
if( count( $matches ) )
|
||||
{
|
||||
preg_match( "/name=['\"](.+?)[\"']/i", $matches[1], $author );
|
||||
preg_match( "/post=['\"](.+?)[\"']/i", $matches[1], $cid );
|
||||
@@ -1162,10 +1186,10 @@ class _LegacyParser
|
||||
/**
|
||||
* Convert flash HTML back into BBCode
|
||||
*
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @return string Converted text
|
||||
*/
|
||||
protected function _parseOldFlash( $matches=array() )
|
||||
protected function _parseOldFlash( array $matches=array() ): string
|
||||
{
|
||||
$f_arr = explode( "+", $matches[1] );
|
||||
|
||||
@@ -1175,10 +1199,10 @@ class _LegacyParser
|
||||
/**
|
||||
* Convert old code tags back into bbcode
|
||||
*
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @return string Converted text
|
||||
*/
|
||||
protected function _parseOldCode( $matches=array() )
|
||||
protected function _parseOldCode( array $matches=array() ): string
|
||||
{
|
||||
return '[code]' . rtrim( str_replace( "</span>", '', preg_replace( "#<span style='.+?'>#is", "", stripslashes( $matches[2] ) ) ) ) . '[/code]';
|
||||
}
|
||||
@@ -1186,20 +1210,20 @@ class _LegacyParser
|
||||
/**
|
||||
* Convert download manager screenshot URLs
|
||||
*
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @param array $matches Data from preg_replace callback
|
||||
* @return string Converted text
|
||||
*/
|
||||
protected function _fixDownloadsScreenshots( $matches )
|
||||
protected function _fixDownloadsScreenshots( array $matches ): string
|
||||
{
|
||||
if( isset( $matches[1] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$screenshot = \IPS\Db::i()->select( 'record_location, record_realname', 'downloads_files_records', array( "record_file_id=? and record_type IN('sslink','ssupload')", (int) $matches[1] ), 'record_id ASC', array( 0, 1 ) )->first();
|
||||
$screenshot = Db::i()->select( 'record_location, record_realname', 'downloads_files_records', array( "record_file_id=? and record_type IN('sslink','ssupload')", (int) $matches[1] ), 'record_id ASC', array( 0, 1 ) )->first();
|
||||
|
||||
return "<img src='{$screenshot['record_location']}' alt='{$screenshot['record_realname']}'>";
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return $matches[0];
|
||||
}
|
||||
@@ -1216,7 +1240,7 @@ class _LegacyParser
|
||||
* @param string $name Name
|
||||
* @return string Converted name
|
||||
*/
|
||||
protected static function _cleanQuoteName( $name )
|
||||
protected static function _cleanQuoteName( string $name ): string
|
||||
{
|
||||
$name = str_replace( "'", ''', $name );
|
||||
$name = str_replace( '$', '$', $name );
|
||||
|
||||
+1082
-1986
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user