Version 4.7.0
This commit is contained in:
1 parent
517a5e1f70
commit
8ba7d43898
1933 files changed
+65613
-11332
No files matched your search
+170
-10
@@ -28,6 +28,11 @@ class _Parser
|
||||
*/
|
||||
const EMOJI_REGEX = '\x{1F468}\x{200D}\x{2764}\x{FE0F}\x{200D}\x{1F48B}\x{200D}\x{1F468}|\x{1F469}\x{200D}\x{2764}\x{FE0F}\x{200D}\x{1F48B}\x{200D}\x{1F468}|\x{1F469}\x{200D}\x{2764}\x{FE0F}\x{200D}\x{1F48B}\x{200D}\x{1F469}|\x{1F9D1}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{1F91D}\x{200D}\x{1F9D1}|\x{1F3F4}\x{E0067}\x{E0062}\x{E0065}\x{E006E}\x{E0067}\x{E007F}|\x{1F3F4}\x{E0067}\x{E0062}\x{E0077}\x{E006C}\x{E0073}\x{E007F}|\x{1F3F4}\x{E0067}\x{E0062}\x{E0073}\x{E0063}\x{E0074}\x{E007F}|\x{1F468}\x{200D}\x{1F469}\x{200D}\x{1F467}\x{200D}\x{1F466}|\x{1F468}\x{200D}\x{1F469}\x{200D}\x{1F466}\x{200D}\x{1F466}|\x{1F468}\x{200D}\x{1F468}\x{200D}\x{1F467}\x{200D}\x{1F467}|\x{1F468}\x{200D}\x{1F468}\x{200D}\x{1F467}\x{200D}\x{1F466}|\x{1F468}\x{200D}\x{1F468}\x{200D}\x{1F466}\x{200D}\x{1F466}|\x{1F469}\x{200D}\x{1F469}\x{200D}\x{1F466}\x{200D}\x{1F466}|\x{1F469}\x{200D}\x{1F469}\x{200D}\x{1F467}\x{200D}\x{1F466}|\x{1F469}\x{200D}\x{1F469}\x{200D}\x{1F467}\x{200D}\x{1F467}|\x{1F468}\x{200D}\x{1F469}\x{200D}\x{1F467}\x{200D}\x{1F467}|\x{1F3CA}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9D1}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2696}\x{FE0F}|\x{1F64D}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F64D}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F64B}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F64B}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F647}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F647}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F646}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F646}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9D1}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2695}\x{FE0F}|\x{1F645}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F645}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9B9}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F3C3}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F3C3}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F64E}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9D1}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2708}\x{FE0F}|\x{1F9D6}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9D6}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9D7}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9D7}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9D8}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F575}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F575}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9B9}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F93D}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F93D}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F93E}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F93E}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9B8}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F64E}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F6A3}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9CD}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9CF}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F3CB}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F3CB}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F3CC}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F3CC}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F939}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F938}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F938}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9CE}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F937}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F937}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9CE}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F935}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F935}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9CF}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F6A3}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F926}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F926}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F3CA}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F939}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9CD}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F6B6}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F6B6}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F468}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2695}\x{FE0F}|\x{1F6B5}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F3C4}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F3C4}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F6B5}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F6B4}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F6B4}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9B8}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F9D8}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F468}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2696}\x{FE0F}|\x{1F9DB}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2642}\x{FE0F}|\x{1F9DA}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2640}\x{FE0F}|\x{1F469}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2708}\x{FE0F}|\x{1F469}[\x{1F3FB}-\x{1F3FF}]?\x{200D}\x{2696Line truncated
|
||||
|
||||
/**
|
||||
* @brief Regex for detecting email addresses
|
||||
*/
|
||||
const EMAIL_REGEX = '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,9}';
|
||||
|
||||
/* !Parser: Bootstrap */
|
||||
|
||||
/**
|
||||
@@ -89,6 +94,11 @@ class _Parser
|
||||
* @brief If cleaning HTML, the HTMLPurifier object
|
||||
*/
|
||||
protected $htmlPurifier = NULL;
|
||||
|
||||
/**
|
||||
* @brief Save on queries and fetch the alt label would just the once
|
||||
*/
|
||||
protected $_altLabelWord = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -454,7 +464,7 @@ class _Parser
|
||||
$element->removeAttribute( 'data-video-embed' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Swap data-video-src for src */
|
||||
$contentVideos = $source->getElementsByTagName( 'source' );
|
||||
foreach( $contentVideos as $element )
|
||||
@@ -496,7 +506,7 @@ class _Parser
|
||||
public static function replaceFileStoreTags( $value )
|
||||
{
|
||||
/* Some tags have multiple __base_url__ replacements, so we have to replace this in a safe way ensuring we only match inside A, IMG, IFRAME and VIDEO tags to prevent tampering */
|
||||
preg_match_all( '#<(img|a|iframe|video|source)([^>]+?)%7B___base_url___%7D([^>]+?)>#i', $value, $matches, PREG_SET_ORDER );
|
||||
preg_match_all( '#<(img|a|iframe|video|audio|source)([^>]+?)%7B___base_url___%7D([^>]+?)>#i', $value, $matches, PREG_SET_ORDER );
|
||||
foreach( $matches as $val )
|
||||
{
|
||||
$changed = $val[0];
|
||||
@@ -512,7 +522,7 @@ class _Parser
|
||||
}
|
||||
}
|
||||
|
||||
$changed = preg_replace( '#(href|src|data\-src|data\-video\-src|data\-fileid|data\-ipshover\-target)=(\'|")%7B___base_url___%7D/#i', '\1=\2<___base_url___>/', $changed );
|
||||
$changed = preg_replace( '#(href|src|data\-src|data\-video\-src|data\-audio\-src|data\-fileid|data\-ipshover\-target)=(\'|")%7B___base_url___%7D/#i', '\1=\2<___base_url___>/', $changed );
|
||||
if ( $changed != $val[0] )
|
||||
{
|
||||
$value = str_replace( $val[0], $changed, $value );
|
||||
@@ -520,7 +530,7 @@ class _Parser
|
||||
}
|
||||
|
||||
/* Replace {fileStore.xxx} with <fileStore.xxx> */
|
||||
$value = preg_replace( '#(srcset|href|data\-src|src|data\-video\-src)=(\'|")(%7B|\{)fileStore\.([\d\w\_]+?)(%7D|\})/#i', '\1=\2<fileStore.\4>/', $value );
|
||||
$value = preg_replace( '#(srcset|href|data\-src|src|data\-video\-src|data\-video\-src)=(\'|")(%7B|\{)fileStore\.([\d\w\_]+?)(%7D|\})/#i', '\1=\2<fileStore.\4>/', $value );
|
||||
|
||||
/* Return */
|
||||
return $value;
|
||||
@@ -678,6 +688,18 @@ class _Parser
|
||||
'data-video-src' => new \HTMLPurifier_AttrDef_URI( TRUE )
|
||||
) );
|
||||
|
||||
/* Audio */
|
||||
$def->addElement('audio', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', array(
|
||||
'controls' => 'Bool',
|
||||
'data-controller' => new \HTMLPurifier_AttrDef_Enum( array( 'core.global.core.embeddedaudio' ) ),
|
||||
'src' => new \HTMLPurifier_AttrDef_URI( TRUE ),
|
||||
'srcset' => new HtmlPurifierSrcsetDef( TRUE ),
|
||||
'media' => 'Text',
|
||||
'type' => 'Text',
|
||||
'data-audio-embed' => 'Text',
|
||||
'data-audio-src' => new \HTMLPurifier_AttrDef_URI( TRUE )
|
||||
));
|
||||
|
||||
/* Picture tag - we don't use it, but RSS imports might */
|
||||
$def->addElement( 'picture', 'Inline', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', array() );
|
||||
}
|
||||
@@ -764,16 +786,33 @@ class _Parser
|
||||
site.com/index.php?app=forums&module=forums&controller=topic&id=1&do=embed
|
||||
Not Allowed: Anything which goes to anything in an /interface directory - e.g.:
|
||||
site.com/core/interface/file/attachment.php - this would automatically cause files to be downloaded
|
||||
Not Allowed: Any file traversal to expose FileSystem directories, e.g:
|
||||
site.com/core/../uploads/monthly_xx_xx/file.js?
|
||||
Not Allowed: URLs to the open proxy:
|
||||
site.com/index.php?app=core&module=system&controller=redirect
|
||||
*/
|
||||
$interfaces = array();
|
||||
$notAllowed = array();
|
||||
foreach( \IPS\Application::enabledApplications() as $app )
|
||||
{
|
||||
$interfaces[] = str_replace( '/', '(?:/{1,})', '(?:/{0,})' . preg_quote( $app->directory . '/interface/', '%' ) );
|
||||
$notAllowed[] = str_replace( '/', '(?:/{1,})', '(?:/{0,})' . preg_quote( $app->directory . '/interface/', '%' ) );
|
||||
}
|
||||
$return[] = '(https?:)?//' . preg_quote( str_replace( array( 'http://', 'https://' ), '', \IPS\Settings::i()->base_url ), '%' ) . '\/?(\?|index\.php\?|(?!' . implode( '|', $interfaces ) . ').+?\?)((?!(controller|section)=redirect).)*$';
|
||||
$return[] = preg_quote( '%7B___base_url___%7D', '%' ) . '\/?(\?|index\.php\?|(?!' . implode( '|', $interfaces ) . ').+?\?)((?!(controller|section)=redirect).)*$';
|
||||
|
||||
foreach( \IPS\File::getStore() as $configuration )
|
||||
{
|
||||
if ( $configuration['method'] == 'FileSystem' and ! empty( $configuration['configuration'] ) and $config = json_decode( $configuration['configuration'], TRUE ) )
|
||||
{
|
||||
if ( !empty( $config['dir'] ) and mb_strpos( $config['dir'], '{root}' ) !== false )
|
||||
{
|
||||
if ( $path = trim( str_replace( '{root}', '', $config['dir'] ), '\/' ) )
|
||||
{
|
||||
$notAllowed[] = '(?:.+?/{1,})\.{1,}(?:/{1,})' . $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$return[] = '(https?:)?//' . preg_quote( str_replace( array( 'http://', 'https://' ), '', \IPS\Settings::i()->base_url ), '%' ) . '\/?(\?|index\.php\?|(?!' . implode( '|', $notAllowed ) . ').+?\?)((?!(controller|section)=redirect).)*$';
|
||||
$return[] = preg_quote( '%7B___base_url___%7D', '%' ) . '\/?(\?|index\.php\?|(?!' . implode( '|', $notAllowed ) . ').+?\?)((?!(controller|section)=redirect).)*$';
|
||||
|
||||
/* Return */
|
||||
return '%^(' . implode( '|', $return ) . ')%';
|
||||
@@ -792,6 +831,7 @@ class _Parser
|
||||
/* Our default embed options */
|
||||
$return = array_merge( $return, array(
|
||||
'www.youtube.com/embed/',
|
||||
'www.youtube-nocookie.com/embed/',
|
||||
'player.vimeo.com/video/',
|
||||
'www.hulu.com/embed.html',
|
||||
'www.collegehumor.com/e/',
|
||||
@@ -809,6 +849,7 @@ class _Parser
|
||||
'www.screencast.com/users/',
|
||||
'fast.wistia.net/embed/',
|
||||
'www.screencast.com/users/',
|
||||
'players.brightcove.net/',
|
||||
) );
|
||||
|
||||
/* Extra admin-defined options */
|
||||
@@ -892,6 +933,11 @@ class _Parser
|
||||
/* Links (Used to replace disallowed URLs */
|
||||
$return[] = 'ipsType_noLinkStyling';
|
||||
|
||||
/* Brightcove */
|
||||
$return[] = 'ipsEmbeddedBrightcove';
|
||||
$return[] = 'ipsEmbeddedBrightcove_inner';
|
||||
$return[] = 'ipsEmbeddedBrightcove_frame';
|
||||
|
||||
/* Custom */
|
||||
if( \IPS\Settings::i()->editor_allowed_classes )
|
||||
{
|
||||
@@ -1387,13 +1433,19 @@ class _Parser
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Emoji? */
|
||||
if ( ( !$originalParent->getAttribute('class') or !\in_array( 'ipsEmoji', explode( ' ', $originalParent->getAttribute('class') ) ) ) and preg_match( '/' . static::EMOJI_REGEX . '/u', $section ) )
|
||||
{
|
||||
$parent = $parent->appendChild( new \DOMElement( 'span' ) );
|
||||
$parent->setAttribute( 'class', 'ipsEmoji' );
|
||||
}
|
||||
|
||||
/* Check for emails */
|
||||
if ( \IPS\Settings::i()->email_filter_action == 'replace' and preg_match( '/' . static::EMAIL_REGEX . '/u', $section ) )
|
||||
{
|
||||
$section = preg_replace( '/' . static::EMAIL_REGEX . '/u', \IPS\Settings::i()->email_filter_replace_text, $section );
|
||||
}
|
||||
|
||||
/* Insert the text */
|
||||
$this->_insertNodeApplyingInlineBBcode( new \DOMText( $section ), $parent );
|
||||
@@ -1699,6 +1751,10 @@ class _Parser
|
||||
$element = $this->_parseVideoElement( $element );
|
||||
break;
|
||||
|
||||
case 'audio':
|
||||
$element = $this->_parseAudioElement( $element, $originalElement );
|
||||
break;
|
||||
|
||||
case 'source':
|
||||
$element = $this->_parseSourceElement( $element, $originalElement );
|
||||
break;
|
||||
@@ -1763,6 +1819,19 @@ class _Parser
|
||||
$element->setAttribute( 'data-fileid', $attachment['attach_id'] );
|
||||
$element->setAttribute( 'href', str_replace( array( 'http:', 'https:' ), '', str_replace( static::$fileObjectClasses['core_Attachment']->baseUrl(), '{fileStore.core_Attachment}', $element->getAttribute('href') ) ) );
|
||||
$element->setAttribute( 'data-fileext', $attachment['attach_ext'] );
|
||||
|
||||
if ( ! empty( $attachment['attach_labels'] ) and $labels = static::getAttachmentLabels( $attachment ) )
|
||||
{
|
||||
if ( \count( $labels ) )
|
||||
{
|
||||
if ( $this->_altLabelWord === NULL )
|
||||
{
|
||||
$this->_altLabelWord = \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'alt_label_could_be' );
|
||||
}
|
||||
|
||||
$element->setAttribute( 'alt', $this->_altLabelWord . ' ' . implode( ', ', $labels ) );
|
||||
}
|
||||
}
|
||||
|
||||
$this->_logAttachment( $attachment );
|
||||
}
|
||||
@@ -1860,6 +1929,20 @@ class _Parser
|
||||
{
|
||||
$element->setAttribute( 'data-fileid', $attachment['attach_id'] );
|
||||
$element->setAttribute( 'src', str_replace( array( 'http:', 'https:' ), '', str_replace( static::$fileObjectClasses['core_Attachment']->baseUrl(), '{fileStore.core_Attachment}', $element->getAttribute( $srcAttribute ) ) ) );
|
||||
|
||||
if ( ! empty( $attachment['attach_labels'] ) and $labels = static::getAttachmentLabels( $attachment ) )
|
||||
{
|
||||
if ( \count( $labels ) )
|
||||
{
|
||||
if ( $this->_altLabelWord === NULL )
|
||||
{
|
||||
$this->_altLabelWord = \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'alt_label_could_be' );
|
||||
}
|
||||
|
||||
$element->setAttribute( 'alt', $this->_altLabelWord . ' ' . implode( ', ', $labels ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$element->getAttribute('alt') )
|
||||
{
|
||||
$element->setAttribute( 'alt', $attachment['attach_file'] );
|
||||
@@ -1940,6 +2023,28 @@ class _Parser
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse <audio> element
|
||||
*
|
||||
* @param \DOMElement $element The element
|
||||
* @return \DOMElement
|
||||
*/
|
||||
protected function _parseAudioElement( \DOMElement $element )
|
||||
{
|
||||
if ( \IPS\Settings::i()->lazy_load_enabled )
|
||||
{
|
||||
$element->removeAttribute( 'data-controller' );
|
||||
$element->setAttribute( 'data-audio-embed', '' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$element->setAttribute( 'data-controller', 'core.global.core.embeddedaudio' );
|
||||
$element->removeAttribute( 'data-audio-embed' );
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse <source> element
|
||||
*
|
||||
@@ -3157,6 +3262,7 @@ class _Parser
|
||||
'ted.com' => array( 'https://www.ted.com/services/v1/oembed', static::EMBED_VIDEO ),
|
||||
'vine.co' => array( 'https://vine.co/oembed.json', static::EMBED_VIDEO ),
|
||||
'dailymotion.com' => array( 'https://www.dailymotion.com/services/oembed', static::EMBED_VIDEO ),
|
||||
'dai.ly' => array( 'https://www.dailymotion.com/services/oembed', static::EMBED_VIDEO ),
|
||||
'coub.com' => array( 'http://coub.com/api/oembed.json' . ( \IPS\Settings::i()->max_video_width ? ( '?maxwidth=' . \IPS\Settings::i()->max_video_width ) : '' ), static::EMBED_VIDEO ),
|
||||
'*.deviantart.com' => array( 'https://backend.deviantart.com/oembed', static::EMBED_IMAGE ),
|
||||
'docs.com' => array( 'http://docs.com/api/oembed', static::EMBED_LINK ),
|
||||
@@ -3478,6 +3584,12 @@ class _Parser
|
||||
/* For Youtube, we need to be a bit hacky to pass rel=0 */
|
||||
if ( $domain == 'youtube.com' or $domain == 'm.youtube.com' or $domain == 'youtu.be' )
|
||||
{
|
||||
/* YouTube has no way to make it return youtube-nocookie from the oEmbed endpoint, so we need to swap it manually. */
|
||||
if ( mb_strpos( $response['html'], 'youtube-nocookie.com/embed' ) === FALSE )
|
||||
{
|
||||
$response['html'] = str_replace( 'youtube.com', 'youtube-nocookie.com', $response['html'] );
|
||||
}
|
||||
|
||||
if ( isset( $url->queryString['rel'] ) )
|
||||
{
|
||||
$response['html'] = str_replace( '?feature=oembed', '?feature=oembed&rel=0', $response['html'] );
|
||||
@@ -3812,6 +3924,40 @@ class _Parser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Brightcove */
|
||||
$domain = $url->data['host'];
|
||||
if( !$domain )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if( $domain == 'bcove.video' or $domain == 'players.brightcove.net' )
|
||||
{
|
||||
/* If using a shortcode we need to redirect to the full URL */
|
||||
if( $domain == 'bcove.video' )
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = $url->request( null, null, 0 )->get();
|
||||
|
||||
if( $response->httpResponseCode == 301 )
|
||||
{
|
||||
$url = \IPS\Http\Url::external( $response->httpHeaders['Location'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \IPS\Http\Request\Exception;
|
||||
}
|
||||
}
|
||||
catch( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
throw new \UnexpectedValueException( 'embed__fail_500', (float) static::EMBED_VIDEO );
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'embed', 'core', 'global' )->brightcove( $url );
|
||||
}
|
||||
|
||||
/* So if it's not that, just return */
|
||||
return NULL;
|
||||
@@ -4356,7 +4502,10 @@ class _Parser
|
||||
{
|
||||
$value = $content->saveHTML();
|
||||
$value = preg_replace( '/<meta http-equiv(?:[^>]+?)>/i', '', preg_replace( '/^<!DOCTYPE.+?>/', '', str_replace( array( '<html>', '</html>', '<body>', '</body>', '<head>', '</head>' ), '', $value ) ) );
|
||||
|
||||
|
||||
/* Replace file storage tags */
|
||||
$value = preg_replace( '/<fileStore\.([\d\w\_]+?)>/i', '<fileStore.$1>', $value );
|
||||
|
||||
/* DOMDocument::saveHTML will encode the base_url brackets, so we need to make sure it's in the expected format. */
|
||||
return str_replace( '<___base_url___>', '<___base_url___>', $value );
|
||||
}
|
||||
@@ -4467,4 +4616,15 @@ class _Parser
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse attachment labels and pull the required data
|
||||
*
|
||||
* @param array $attachment Row from core_attachments
|
||||
* @return array
|
||||
*/
|
||||
public static function getAttachmentLabels( $attachment ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user