41 $html = (string) $html;
48 $mincharsperimg =
getDolGlobalInt(
'SIGNATURE_QUALITY_MIN_CHARS_PER_IMG', 60);
55 'non_absolute_url' => 25,
56 'text_image_ratio_error' => 55,
57 'text_image_ratio_warning' => 12,
58 'image_count_error' => 20,
59 'image_count_warning' => 10,
60 'image_alt_per_image' => 5,
61 'image_alt_cap' => 15,
70 $insufficientcontentcap = 35;
73 'content',
'script_tag',
'style_block',
'non_absolute_url',
'text_image_ratio',
74 'image_count',
'image_alt',
'image_weight',
'link_count',
'text_length',
75 'contact_info',
'fixed_width',
78 foreach ($codes as $code) {
79 $checks[$code] = array(
'status' =>
'ok',
'weight' => 0);
83 $set =
function (
string $code,
string $status,
int $weight) use (&$checks, &$score) {
84 $checks[$code] = array(
'status' => $status,
'weight' => $weight);
89 $htmlnoscript = preg_replace(
'/<(script|style)\b[^>]*>.*?<\/\1>/is',
' ', $html);
91 $text = trim((
string) preg_replace(
'/\s+/u',
' ', (
string) $text));
92 $textlen = function_exists(
'mb_strlen') ? mb_strlen($text,
'UTF-8') : strlen($text);
93 $wordcount = preg_match_all(
'/\p{L}{2,}/u', $text);
97 preg_match_all(
'/<img\b[^>]*>/i', $html, $matches);
98 $imgtags = $matches[0];
99 $nbimg = count($imgtags);
102 if ($textlen == 0 && $nbimg == 0) {
103 $checks[
'content'][
'status'] =
'error';
104 $checks[
'text_image_ratio'][
'status'] =
'error';
105 $checks[
'text_length'][
'status'] =
'error';
106 $checks[
'contact_info'][
'status'] =
'error';
107 return array(
'score' => 0,
'grade' =>
'poor',
'checks' => $checks);
111 $insufficientcontent = ($nbimg == 0 && ($textlen < $mintextlen || $wordcount < 2));
112 if ($insufficientcontent) {
113 $set(
'content',
'error', 0);
117 if (preg_match(
'/<script\b/i', $html)) {
118 $set(
'script_tag',
'error', $w[
'script_tag']);
120 if (preg_match(
'/<style\b/i', $html) || preg_match(
'/<link\b[^>]*stylesheet/i', $html)) {
121 $set(
'style_block',
'warning', $w[
'style_block']);
126 $hasnonabsolute =
false;
127 $hasheavyimg =
false;
128 foreach ($imgtags as $tag) {
130 if (preg_match(
'/\ssrc\s*=\s*("|\')(.*?)\1/is', $tag, $ms)) {
131 $src = trim(html_entity_decode($ms[2], ENT_QUOTES,
'UTF-8'));
134 if ($src ===
'' || (!preg_match(
'#^(https:)?//#i', $src) && strpos($src,
'data:') !== 0)) {
135 $hasnonabsolute =
true;
137 if (strpos($src,
'data:') === 0) {
140 if (!preg_match(
'/\salt\s*=\s*("|\')(.*?)\1/is', $tag) && !preg_match(
'/\salt\s*=\s*[^"\'\s>]+/i', $tag)) {
143 if (preg_match(
'/\swidth\s*=\s*("|\')?\s*(\d+)/i', $tag, $mw) && (
int) $mw[2] > $maximgwidth) {
146 if (preg_match(
'/width\s*:\s*(\d+)\s*px/i', $tag, $mw2) && (
int) $mw2[1] > $maximgwidth) {
151 if ($hasnonabsolute) {
152 $set(
'non_absolute_url',
'error', $w[
'non_absolute_url']);
157 $ratio = $textlen / $nbimg;
158 if ($textlen < 10 || $ratio < 20) {
159 $set(
'text_image_ratio',
'error', $w[
'text_image_ratio_error']);
160 } elseif ($ratio < $mincharsperimg) {
161 $set(
'text_image_ratio',
'warning', $w[
'text_image_ratio_warning']);
166 if ($nbimg > 2 * $maximg) {
167 $set(
'image_count',
'error', $w[
'image_count_error']);
168 } elseif ($nbimg > $maximg) {
169 $set(
'image_count',
'warning', $w[
'image_count_warning']);
173 if ($nbimgnoalt > 0) {
174 $set(
'image_alt',
'warning', min($w[
'image_alt_cap'], $nbimgnoalt * $w[
'image_alt_per_image']));
179 $set(
'image_weight',
'warning', $w[
'image_weight']);
183 $nblinks = preg_match_all(
'/<a\b[^>]*\shref\s*=/i', $html);
184 if ($nblinks > $maxlinks) {
185 $set(
'link_count',
'warning', $w[
'link_count']);
189 if ($textlen > $maxtextlen) {
190 $set(
'text_length',
'warning', $w[
'text_length']);
194 $hascontact = (preg_match(
'/mailto:/i', $html) || preg_match(
'/tel:/i', $html)
195 || preg_match(
'/[\w.+-]+@[\w-]+\.[\w.-]+/', $text) || preg_match(
'/[\w.+-]+@[\w-]+\.[\w.-]+/', $html));
197 $set(
'contact_info',
'warning', $w[
'contact_info']);
202 if (preg_match_all(
'/<(?:table|td|div)\b[^>]*\swidth\s*=\s*("|\')?\s*(\d+)/i', $html, $mfw)) {
203 foreach ($mfw[2] as $wv) {
204 if ((
int) $wv > $maximgwidth) {
211 $set(
'fixed_width',
'warning', $w[
'fixed_width']);
214 if ($insufficientcontent) {
215 $score = min($score, $insufficientcontentcap);
218 $score = max(0, min(100, $score));
221 $grade =
'excellent';
222 } elseif ($score >= 65) {
224 } elseif ($score >= 40) {
230 return array(
'score' => (
int) $score,
'grade' => $grade,
'checks' => $checks);
246 if (!is_object($outputlangs)) {
247 $outputlangs = $langs;
249 $outputlangs->load(
'users');
251 if (trim((
string) $html) ===
'') {
257 $gradecolors = array(
258 'excellent' =>
'#1a9850',
263 $color = isset($gradecolors[$res[
'grade']]) ? $gradecolors[$res[
'grade']] :
'#999999';
264 $gradelabel = $outputlangs->trans(
'SignatureQuality'.ucfirst($res[
'grade']));
266 $out =
'<div class="signaturequalityscore paddingtop">';
267 $out .=
'<span class="badge" style="background-color: '.$color.
';" title="'.
dol_escape_htmltag($outputlangs->trans(
'SignatureQualityTooltip')).
'">';
272 foreach ($res[
'checks'] as $code => $check) {
273 if ($check[
'status'] ===
'ok') {
276 $key =
'SignatureCheck'.str_replace(
' ',
'', ucwords(str_replace(
'_',
' ', $code)));
277 $advkey =
'SignatureAdvice'.str_replace(
' ',
'', ucwords(str_replace(
'_',
' ', $code)));
278 $icon = ($check[
'status'] ===
'error' ? img_picto(
'',
'error') : img_picto(
'',
'warning'));
282 if (count($issues)) {
283 $out .=
' <details class="signaturequalitydetails inline-block">';
284 $out .=
'<summary class="cursorpointer">'.dol_escape_htmltag($outputlangs->trans(
'SignatureQualityDetails')).
'</summary>';
285 $out .=
'<ul class="nomargin">'.implode(
'', $issues).
'</ul>';
286 $out .=
'</details>';
288 $out .=
' <span class="opacitymedium">'.dol_escape_htmltag($outputlangs->trans(
'SignatureQualityNoIssue')).
'</span>';
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)