Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/Cleantalk/Common/ContactsEncoder/ContactsEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ public function modifyGlobalEmails($content)

$position = $this->advanceMatchCursor($matches[0], $match_cursor);

if ( $this->exclusions->isContactExcluded($matches[0]) ) {
return $matches[0];
}
Comment thread
svedge marked this conversation as resolved.

if ( isset($matches[3]) && in_array(strtolower($matches[3]), ['.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp']) ) {
return $matches[0];
}
Expand Down Expand Up @@ -372,6 +376,10 @@ function ($matches) use (&$match_cursor) {

$position = $this->advanceMatchCursor($matches[0], $match_cursor);

if ( $this->exclusions->isContactExcluded($matches[0]) ) {
return $matches[0];
}

if ( $this->helper->isTelTag($matches[0]) ) {
return $this->encodeTelLink($matches[0]);
}
Expand Down
7 changes: 7 additions & 0 deletions lib/Cleantalk/Common/ContactsEncoder/Dto/Params.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ class Params
public $obfuscation_text = 'hidden contact data';
public $do_encode_emails = 1;
public $do_encode_phones = 0;

/**
* Emails, phones or text fragments that must never be encoded.
*
* @var string[]
*/
public $excluded_strings = array();
Comment thread
svedge marked this conversation as resolved.
}
121 changes: 121 additions & 0 deletions lib/Cleantalk/Common/ContactsEncoder/Exclusions/ExclusionsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,125 @@ protected function byLoggedIn()
{
return $this->params->is_logged_in;
}

/**
* Split a settings textarea into unique non-empty exclusion strings (one value per line).
*
* @param string $raw
*
* @return string[]
* @psalm-suppress PossiblyUnusedMethod Public API for host apps that store the list as raw text
*/
public static function parseExcludedStrings($raw)
{
if ( ! is_string($raw) || $raw === '' ) {
return array();
}

$parts = preg_split('/\R+/', $raw);
if ( ! is_array($parts) ) {
return array();
}

$result = array();
foreach ( $parts as $part ) {
$part = trim($part, " \n\r\t\v\x00");
if ( $part !== '' ) {
$result[] = $part;
}
}

return array_values(array_unique($result));
}

/**
* Whether a matched email or phone must stay unencoded.
*
* @param string $match
*
* @return bool
*/
public function isContactExcluded($match)
Comment thread
svedge marked this conversation as resolved.
{
if ( ! is_string($match) || $match === '' ) {
return false;
}

if ( empty($this->params->excluded_strings) || ! is_array($this->params->excluded_strings) ) {
return false;
}

$normalized_match = $this->normalizeContactString($match);
$match_digits = $this->extractDigits($match);

foreach ( $this->params->excluded_strings as $exclusion ) {
if ( ! is_string($exclusion) || $exclusion === '' ) {
continue;
}

$normalized_exclusion = $this->normalizeContactString($exclusion);
if ( $normalized_exclusion === '' ) {
continue;
}

if ( $normalized_match === $normalized_exclusion ) {
return true;
}

if ( strpos($normalized_match, $normalized_exclusion) !== false ) {
return true;
}

// Digit compare is for phones only. Emails with long number sequences
// must not match an excluded phone (or the other way around).
if (
strpos($normalized_match, '@') === false
&& strpos($normalized_exclusion, '@') === false
) {
$exclusion_digits = $this->extractDigits($exclusion);
if (
strlen($exclusion_digits) >= 8
&& strlen($match_digits) >= 8
&& (
strpos($match_digits, $exclusion_digits) !== false
|| strpos($exclusion_digits, $match_digits) !== false
)
) {
return true;
}
}
}

return false;
}

/**
* @param string $value
*
* @return string
*/
private function normalizeContactString($value)
{
$value = trim($value, " \n\r\t\v\x00");
if ( stripos($value, 'mailto:') === 0 ) {
$value = substr($value, 7);
}
if ( stripos($value, 'tel:') === 0 ) {
$value = substr($value, 4);
}

return strtolower(trim($value, " \n\r\t\v\x00"));
}

/**
* @param string $value
*
* @return string
*/
private function extractDigits($value)
{
$digits = preg_replace('/\D+/', '', $value);

return is_string($digits) ? $digits : '';
}
}
5 changes: 4 additions & 1 deletion lib/Cleantalk/Common/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ public static function ipResolve($ip)
* Resolve DNS to IP
*
* @param $host
* @param false|string $out
Comment thread
svedge marked this conversation as resolved.
Outdated
*
* @return false|string
* @psalm-suppress PossiblyUnusedMethod
Expand Down Expand Up @@ -925,7 +926,9 @@ public static function getMimeType($data, $type = '')
} elseif (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_buffer($finfo, $data);
finfo_close($finfo);
if (PHP_VERSION_ID < 80000) {
finfo_close($finfo);
}
}

// @ToDo the method must return comparison result: return $type === mime_content_type($data)
Expand Down
11 changes: 11 additions & 0 deletions tests/Common/HelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,15 @@ public function test_ipResolve_return_type()
'ipResolve should return false or a non-empty string hostname'
);
}

/**
* Detect MIME from a data buffer. Must not call deprecated finfo_close() on PHP 8.5+.
*/
public function test_getMimeType_from_buffer()
{
$type = Helper::getMimeType('<html><body>hello</body></html>', 'text/plain');

$this->assertIsString($type);
$this->assertNotSame('', $type);
}
}
Loading