diff options
-rw-r--r-- | it.class | 6 | ||||
-rw-r--r-- | it_html.class | 11 | ||||
-rw-r--r-- | it_mail.class | 11 | ||||
-rw-r--r-- | it_url.class | 2 | ||||
-rwxr-xr-x | test/it_html.t | 12 | ||||
-rw-r--r-- | test/it_url.testserver.php | 4 | ||||
-rwxr-xr-x | test/it_url_slow.t | 7 |
7 files changed, 35 insertions, 18 deletions
@@ -1050,8 +1050,8 @@ static function time() /** * Output formatted and localized date - * @param format optional format (default is 2007-01-02 03:04:05). - * Other formats are "date", "datetime", "time". + * @param format optional format to be passed to date(), default "Y-m-d H:i:s" + * Other formats are "date", "datetime" and "time" in local language * Formats can be qualified with language, e.g. "date:en" * Special formats without language support are "icsdate", "icsdatetime". * @param stamp optional unix timestamp (default is now). @@ -1266,7 +1266,7 @@ static function json_encode($data, $p = []) */ static function json_decode($json, $p = []) { - return ($data = json_decode($json, $p['assoc'])) === null && trim($json) != 'null' ? it::error((array)$p['it_error'] + ['title' => "invalid json: " . json_last_error(), 'body' => $json]) : $data; + return ($data = json_decode($json, $p['assoc'])) === null && trim($json) != 'null' ? it::error((array)$p['it_error'] + ['title' => "invalid json: " . json_last_error_msg(), 'body' => $json]) : $data; } /** diff --git a/it_html.class b/it_html.class index e3053b6..9bb8e7a 100644 --- a/it_html.class +++ b/it_html.class @@ -393,32 +393,33 @@ static function sanitize($html) if ($charset == "utf-8") $html = it::any2utf8($html); $html = it::replace(array('[\0\s]+' => " "), $html); # \s also matches \r and \n - $urlpattern = 'https?://[^">]+'; + $urlpattern = '(?:https?://|mailto:)[^">]+'; + $placeholder = bin2hex(random_bytes(16)); if ($tag = it::match("(.*?)<(div|p|ol|ul|li|i|b|strong|h[1-6])\b[^>]*>(.*?)</\\2>(.*)", $html)) { # Simple tags with content, no attributes kept list($head, $tagname, $content, $tail) = $tag; $tagname = strtolower($tagname); - $result .= it_html::sanitize($head) . "<$tagname>" . it_html::sanitize($content) . "</$tagname>" . it_html::sanitize($tail); + $result .= it::replace([$placeholder => "<$tagname>" . it_html::sanitize($content) . "</$tagname>"], it_html::sanitize("$head$placeholder$tail")); } else if ($tag = it::match('(.*)<a\b[^>]+?\bhref\s*=\s*"(' . $urlpattern . ')"[^>]*?>(.*?)</a>(.*)', $html)) { # Link tags, keeps only href attribute list($head, $href, $content, $tail) = $tag; - $result .= it_html::sanitize($head) . '<a href="' . it_html::Q(it_html::U(html_entity_decode($href, ENT_COMPAT, $charset))) . '">' . it_html::sanitize($content) . "</a>" . it_html::sanitize($tail); + $result .= it::replace([$placeholder => '<a href="' . it_html::Q(it_html::U(html_entity_decode($href, ENT_COMPAT, $charset))) . '">' . it_html::sanitize($content) . "</a>"], it_html::sanitize("$head$placeholder$tail")); } else if ($tag = it::match('(.*)<img\b[^>]+?\bsrc\s*=\s*"(' . $urlpattern . ')"[^>]*?>(.*)', $html)) { # Image tags, keeps only src attribute list($head, $src, $tail) = $tag; - $result .= it_html::sanitize($head) . '<img src="' . it_html::Q(it_html::U(html_entity_decode($src, ENT_COMPAT, $charset))) . '" alt="" />' . it_html::sanitize($tail); + $result .= it::replace([$placeholder => '<img src="' . it_html::Q(it_html::U(html_entity_decode($src, ENT_COMPAT, $charset))) . '" alt="" />'], it_html::sanitize("$head$placeholder$tail")); } else if ($tag = it::match("(.*)<(br|/tr)\b[^>]*>(.*)", $html)) { # brs and table rows are converted so simple line breaks list($head, $tagname, $tail) = $tag; - $result .= it_html::sanitize($head) . "<br />" . it_html::sanitize($tail); + $result .= it::replace([$placeholder => "<br />"], it_html::sanitize("$head$placeholder$tail")); } else $result = it::replace(array('&(#\d+;)' => '&$1'), it_html::Q(html_entity_decode(strip_tags($html), ENT_COMPAT, $charset))); diff --git a/it_mail.class b/it_mail.class index 11a4252..3d57bc3 100644 --- a/it_mail.class +++ b/it_mail.class @@ -575,22 +575,17 @@ static function check_email($email, $checkmailbox = false) $finished = false; $connected = 0; - if (function_exists('stream_set_timeout')) - $timeout = 'stream_set_timeout'; - else - $timeout = 'socket_set_timeout'; - foreach ($mx as $mxhost => $dummy_weight) { if ($fp = @fsockopen($mxhost, $port, $dummy_errno, $dummy_errstr, 5)) { $connected++; - $timeout($fp, 45); + stream_set_timeout($fp, 45); $answer = ''; if (it_mail::send_smtp_cmd($fp, '', $answer) && it_mail::send_smtp_cmd($fp, "HELO $fromdomain", $answer) && it_mail::send_smtp_cmd($fp, "MAIL FROM: <$from>", $answer)) { - $timeout($fp, 2); + stream_set_timeout($fp, 2); $timeoutok = ($domain != 'bluewin.ch'); if (it_mail::send_smtp_cmd($fp, "RCPT TO: <$email>", $answer, $timeoutok, 500)) # 450 is often used for Greylisting @@ -602,7 +597,7 @@ static function check_email($email, $checkmailbox = false) $finished = true; } - $timeout($fp, 0, 1); + stream_set_timeout($fp, 0, 1); it_mail::send_smtp_cmd($fp, 'RSET', $answer); diff --git a/it_url.class b/it_url.class index 8af61ae..c814261 100644 --- a/it_url.class +++ b/it_url.class @@ -314,8 +314,6 @@ function request($p=array()) curl_setopt($curl, CURLOPT_URL, $url->url); } - - # FIXME 2025-01 NG just use CURLOPT_MAXFILESIZE if we have curl 8.4 $content = ""; if ($p['maxlength'] && !$p['writefunction']) { diff --git a/test/it_html.t b/test/it_html.t index 15f444d..20ab65f 100755 --- a/test/it_html.t +++ b/test/it_html.t @@ -260,6 +260,18 @@ is( ); is( + it_html::sanitize('<a href="http://search.ch/"><strong>foo</strong></a>'), + '<a href="http://search.ch/"><strong>foo</strong></a>', + 'it_html::sanitize handle nesting of tags inside <a>' +); + +is( + it_html::sanitize('<a href="mailto:neuman@example.com">foo</a>'), + '<a href="mailto:neuman@example.com">foo</a>', + 'it_html::sanitize handle mailto links' +); + +is( it_html::sanitize("<a href='http://search.ch/'>foo</a>"), '<a href="http://search.ch/">foo</a>', 'TODO it_html::sanitize handle anchors with single quotes at attribute value' diff --git a/test/it_url.testserver.php b/test/it_url.testserver.php index ca5300c..e59a81a 100644 --- a/test/it_url.testserver.php +++ b/test/it_url.testserver.php @@ -66,8 +66,12 @@ switch ($_SERVER['PHP_SELF']) break; case "/repeat": + if ($_REQUEST['compressed']) + ob_start('ob_gzhandler'); for ($i = 0; $i < $_REQUEST['num']; $i++) echo $_REQUEST['string']; + if ($_REQUEST['compressed']) + ob_end_flush(); break; case "/empty": diff --git a/test/it_url_slow.t b/test/it_url_slow.t index 00bbc2f..a5fd348 100755 --- a/test/it_url_slow.t +++ b/test/it_url_slow.t @@ -69,6 +69,13 @@ if (!$res || !$res2) handle_server( ok( + !it_url::get(['url' => "http://$host/repeat?string=abcdefghijklmnop&num=10&compressed", 'maxlength' => 100, 'retries' => 0, 'it_error' => false]), + 'it_url::get() fails for response larger than maxlength even if compressed response is smaller' + ) +); + +handle_server( + ok( it_url::get(U("http://$host/repeat", ['string' => "abc", 'num' => 1024 * 1024])) == str_repeat("abc", 1024 * 1024), 'it_url::get() handles large response' ) |