PluginProbe
Tracking Code Manager / 2.3.0
Tracking Code Manager v2.3.0
2.8.0 2.7.0 trunk 1.11.8 1.11.9 1.12.0 1.12.1 1.12.2 1.12.3 1.4 1.5 2.0.0 2.0.1 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.2.0 All 29 releases
tracking-code-manager / includes / classes / html / HTMLContext.php
HTMLContext.php
570 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit;
3
4 class IRP_HTMLContext {
5 var $root; //MainTag
6 var $buffer; //IRP_Stack
7
8 var $uncuttable;
9 var $withoutNextState;
10 var $withoutNextWords;
11 var $isParentTable;
12
13 var $currentWords;
14 var $lastBoxWords;
15 //last time that the plugin insert the related posts box counter values
16 var $wordsThreshold;
17 var $skipWordsCount=FALSE;
18
19 public function __construct() {
20 $this->clearBuffer();
21 }
22
23 public function setWithoutNextBox() {
24 $this->withoutNextState=TRUE;
25 $this->withoutNextWords=$this->currentWords;
26 }
27 public function isSkipCurrentBox() {
28 $result=FALSE;
29 if($this->withoutNextState) {
30 //if i already had written some words i can unlock the withoutNext lock
31 $result=($this->currentWords<=$this->withoutNextWords);
32 if(!$result) {
33 $this->withoutNextState=FALSE;
34 $this->withoutNextWords=0;
35 }
36 }
37 return $result;
38 }
39 public function clearSkipNext() {
40 $this->withoutNextState=FALSE;
41 $this->withoutNextWords=0;
42 }
43
44 public function setUncuttable($value) {
45 $this->uncuttable=$value;
46 }
47 public function isUncuttable() {
48 return $this->uncuttable;
49 }
50
51 private function clearBuffer() {
52 $this->buffer=new IRP_Stack();
53 $this->uncuttable=FALSE;
54 $this->isParentTable=FALSE;
55 $this->withoutNextState=FALSE;
56 $this->currentWords=0;
57 $this->lastBoxWords=0;
58 $this->withoutNextState=FALSE;
59 $this->withoutNextWords=0;
60 }
61 private function pushTextContent($part, $text, IRP_Stack &$tagsStack) {
62 if(!$part) {
63 $parent=$tagsStack->peek();
64 $part=new IRP_TextContent();
65 $parent->pushTag($part);
66 }
67 $part->append($text);
68 return $part;
69 }
70
71 public function isWriteRelatedBox() {
72 global $irp;
73 if($this->isSkipCurrentBox()) {
74 return FALSE;
75 }
76 if($this->isUncuttable()) {
77 return FALSE;
78 }
79
80 $irp->Log->debug('WriteRelatedBox?');
81 $diff=($this->currentWords-$this->lastBoxWords);
82 $irp->Log->debug('currentWords[%s]-lastBoxWords[%s]=diff[%s]'
83 , $this->currentWords, $this->lastBoxWords, $diff);
84
85 $postLimit=$this->wordsThreshold*($irp->Options->getRewriteBoxesWritten()+1);
86 $irp->Log->debug('wordsThreshold[%s]*(RewriteBoxesWritten[%s]+1)=postLimit[%s]'
87 , $this->wordsThreshold, $irp->Options->getRewriteBoxesWritten(), $postLimit);
88
89 $minLimit=$irp->Options->getRewriteThreshold();
90 $result=($this->currentWords>=$postLimit && $diff>=$minLimit);
91 $irp->Log->debug('(currentWords[%s]>=postLimit[%s]) AND (diff[%s]>=minLimit[%s])=%s'
92 , $this->currentWords, $postLimit
93 , $diff, $minLimit, $result);
94 return $result;
95 }
96
97 function getTagAttribute($fullTag, $name) {
98 $close=strpos($fullTag, '>');
99 $attr=strpos($fullTag, ' '.$name.'=');
100 $result='';
101 if($attr!==FALSE && $close!==FALSE && $attr<$close) {
102 $quote=substr($fullTag, $attr+strlen($name)+2, 1);
103 $text=substr($fullTag, $attr+strlen($name)+3);
104 $end=strpos($text, $quote, 1);
105 if($end!==FALSE) {
106 $result=substr($text, 0, $end);
107 }
108 }
109 return $result;
110 }
111
112 //get the tag name to lower case, could be that is not defined
113 //so this function return '' could also be that
114 function getTagName($fullTag) {
115 global $irp;
116
117 $start=1;
118 $p=strpos($fullTag, ' ');
119 if($p===FALSE) {
120 $p=strpos($fullTag, '/');
121 if($p!==FALSE && $p==1) {
122 $start=2;
123 $p=FALSE;
124 }
125 if($p===FALSE) {
126 $p=strpos($fullTag, '>');
127 if($p===FALSE) {
128 $irp->Log->error('UNABLE TO DECODE TAG %s', $fullTag);
129 return '';
130 }
131 }
132 }
133 $tag=trim(substr($fullTag, $start, $p-$start));
134 $tag=strtolower($tag);
135 if ($irp->Utils->startsWith($tag, '!--')) {
136 $tag = '';
137 }
138 return $tag;
139 }
140 function getHtmlTag($fullTag){
141 global $irp;
142
143 $tag=$this->getTagName($fullTag);
144 $tagId=$this->getTagAttribute($fullTag, 'id');
145 $tagClasses=$this->getTagAttribute($fullTag, 'class');
146 if($tagClasses!=='') {
147 $tagClasses=explode(' ', $tagClasses);
148 } else {
149 $tagClasses=array();
150 }
151
152 if($tag=='') {
153 return NULL;
154 }
155
156 $result=new IRP_OtherTag();
157 if (stripos($fullTag, '/>') !== false) {
158 $result=new IRP_SingletonTag();
159 } elseif(in_array($tag, array('h1','h2','h3','h4','h5','h6'))) {
160 $result=new IRP_BehaviourTag();
161 $result->allowBoxBefore=TRUE;
162 $result->ensureUncuttable=TRUE;
163 $result->ensureWithoutNextBox=TRUE;
164 } elseif(in_array($tag, array('ul', 'ol', 'dl'))) {
165 $result=new IRP_BehaviourTag();
166 $result->ensureWithoutPreviousBox=TRUE;
167 $result->ensureUncuttable=TRUE;
168 $result->allowBoxAfter=TRUE;
169 } elseif(in_array($tag, array('area','base','col','br','command','embed','hr','img','input','link','meta','param','source'))) {
170 $result=new IRP_SingletonTag();
171 } elseif(in_array($tag, array('iframe'))) {
172 $result=new IRP_BehaviourTag();
173 $result->allowBoxBefore=TRUE;
174 $result->ensureUncuttable=TRUE;
175 $result->allowBoxAfter=TRUE;
176 $result->skipWordsCount=TRUE;
177 } elseif(in_array($tag, array('table'))) {
178 $result=new IRP_BehaviourTag();
179 $result->allowBoxBefore=TRUE;
180 $result->ensureUncuttable=TRUE;
181 $result->allowBoxAfter=TRUE;
182 } elseif(in_array($tag, array('span'))) {
183 $result=new IRP_BehaviourTag();
184 if ($irp->Options->isPlaceInsideSpanElements()) {
185 $result->ensureWithoutPreviousBox = false;
186 $result->ensureWithoutNextBox = false;
187 } else {
188 $result->ensureWithoutPreviousBox = true;
189 $result->ensureWithoutNextBox = true;
190 }
191 } elseif(in_array($tag, array('figure'))) {
192 $result=new IRP_BehaviourTag();
193 $result->ensureWithoutNextBox=TRUE;
194 $result->skipWordsCount=TRUE;
195 $result->ensureUncuttable=TRUE;
196 } elseif(in_array($tag, array('div'))) {
197 $result=new IRP_BehaviourTag();
198 $result->ensureWithoutPreviousBox=TRUE;
199 $result->ensureWithoutNextBox=TRUE;
200
201 $ids=explode('|', 'optinforms-|wpautbox-|wpurp-container-recipe-');
202 if($irp->Utils->startsWith($tagId, $ids)) {
203 $result->skipWordsCount=TRUE;
204 $result->ensureUncuttable=TRUE;
205 }
206
207 $classes=explode('|', 'yuzo_related_post|shareaholic-|wp-caption|wordpress-post-tabs|amp-wp-article-content|title-wrapper|sa-source-wrapper|et_pb_text_inner|wprm-recipe-name|toc_light_blue|ast-oembed-container|depiction|wc-tab|gkblock-3|et_pb_toggle_content|et_pb_module|aawp-product__description|fusion-text|fusion-alert-content|mv-create-instructions|recipe-ingredients-wrap|guide-box|underPostOptin|x-columnize|counter-hierarchy|counter-flat|review-feature');
208 if($irp->Utils->startsWith($tagClasses, $classes)) {
209 $result->skipWordsCount=TRUE;
210 $result->ensureUncuttable=TRUE;
211 }
212 } elseif(in_array($tag, array('p'))) {
213 $result=new IRP_BehaviourTag();
214 $result->allowBoxBefore=TRUE;
215 $result->allowBoxAfter=TRUE;
216 } elseif(in_array($tag, array('blockquote', 'cite', 'code', 'em', 'pre'))) {
217 $result=new IRP_BehaviourTag();
218 $result->ensureWithoutPreviousBox=TRUE;
219 $result->ensureUncuttable=TRUE;
220 $result->ensureWithoutNextBox=TRUE;
221 } elseif(in_array($tag, array('irp', 'script', 'style'))) {
222 $result=new IRP_BehaviourTag();
223 $result->ensureWithoutPreviousBox=TRUE;
224 $result->ensureUncuttable=TRUE;
225 $result->ensureWithoutNextBox=TRUE;
226 $result->skipWordsCount=TRUE;
227 } elseif(in_array($tag, array('sub', 'sup'))) {
228 $result=new IRP_BehaviourTag();
229 $result->ensureUncuttable=TRUE;
230 }
231 return $result;
232 }
233
234 public function decode($all) {
235 global $irp;
236
237 $this->root=new IRP_MainTag();
238 $this->clearBuffer();
239
240 if(!$all || trim($all)=='') return FALSE;
241
242 //qui sono a ricercare tutti i tag per poi farci delle verifiche
243 $tagsStack=new IRP_Stack();
244 $tagsStack->push($this->root);
245
246 $errors=FALSE;
247 $part=NULL;
248 $previous=0;
249
250 try {
251 do {
252 $less=strpos($all, '<', $previous);
253 if($less===FALSE) {
254 if($previous!=strlen($all)) {
255 $text=$irp->Utils->substrln($all, $previous);
256 $part=$this->pushTextContent($part, $text, $tagsStack);
257 }
258 break;
259 }
260
261 if($previous!=$less) {
262 $text=$irp->Utils->substrln($all, $previous, $less);
263 $part=$this->pushTextContent($part, $text, $tagsStack);
264 }
265
266 $more=strpos($all, '>', $less+1);
267 $another=strpos($all, '<', $less+1);
268 if($more===FALSE) {
269 //only open tag so I considate all as text (in this case is better
270 //to use html code like &gt; or &lt;
271 $text=$irp->Utils->substrln($all, $previous);
272 $part=$this->pushTextContent($part, $text, $tagsStack);
273 break;
274 }
275
276 if($another!==FALSE && $another<$more) {
277 //something like this <bla bla bla <bla bla> so we considerate
278 //from the last < before >
279 $previous=$another;
280 $text=$irp->Utils->substrln($all, $less, $previous);
281 $part=$this->pushTextContent($part, $text, $tagsStack);
282 continue;
283 }
284
285 $previous=$more+1;
286 $text=$irp->Utils->substrln($all, $less, $previous);
287 $parent=$tagsStack->peek();
288 $tag=$this->getOpenTag($text);
289 if($tag) {
290 //detected tag open
291 $part=NULL;
292 $parent->pushTag($tag);
293 if($tag->hasTagContent()) {
294 //this tag contains a content
295 $tagsStack->push($tag);
296 }
297 } else {
298 //detected tag close
299 $tag=$this->getCloseTag($text, $tagsStack);
300 if($tag) {
301 $part=NULL;
302 $compare=$tagsStack->pop();
303 while(!$tagsStack->isEmpty() && $compare!=$tag) {
304 //security check: close each tag until i found my tag
305 $irp->Log->error('WHAT? UNABLE TO FIND OPENED TAG..TRY CLOSING AND RETRYING AGAIN');
306 $compare->closeTag='</'.$compare->tag.'>';
307 $compare=$tagsStack->pop();
308 }
309 if($compare!=$tag) {
310 $irp->Log->error('WHAT? UNABLE TO FIND OPENED TAG');
311 $errors=TRUE;
312 } else {
313 $compare->closeTag=$text;
314 }
315 } else {
316 //simply text
317 $part=$this->pushTextContent($part, $text, $tagsStack);
318 }
319 }
320 }
321 while($previous<strlen($all));
322 } catch(Exception $ex) {
323 $irp->Log->exception($ex);
324 }
325
326 return !$errors;
327 }
328
329 private function getOpenTag($openTag) {
330 global $irp;
331 if($irp->Utils->startsWith($openTag, '</')) {
332 return NULL;
333 }
334
335 $name=$this->getTagName($openTag);
336 $tag=$this->getHtmlTag($openTag);
337 if($tag) {
338 $tag->tag=$name;
339 $tag->openTag=$openTag;
340 }
341 return $tag;
342 }
343 private function getCloseTag($closeTag, IRP_Stack $tagsStack) {
344 global $irp;
345 if(!$irp->Utils->startsWith($closeTag, '</')) {
346 return NULL;
347 }
348
349 $compare=$this->getTagName($closeTag);
350 if($compare=='') return NULL;
351
352 $tos=$tagsStack->peek();
353 if(!$tos || !isset($tos->tag) || strcasecmp($tos->tag, $compare)!=0) {
354 $irp->Log->error('CHECK YOU BODY TAG %s ENDS WITH %s TAG', $tos->tag, $compare);
355 return NULL;
356 }
357
358 $tos->closeTag=$closeTag;
359 return $tos;
360 }
361
362 public function execute($body) {
363 global $irp;
364 if(!$irp->Options->isRewriteActive()) {
365 return $body;
366 }
367
368 $this->decode($body);
369 $this->root->analyseText($this);
370 $t=intval($this->currentWords/($irp->Options->getRewriteBoxesCount()+1));
371 if($t<$irp->Options->getRewriteThreshold()) {
372 $t=$irp->Options->getRewriteThreshold();
373 }
374
375 $this->wordsThreshold=$t;
376
377 $this->clearBuffer();
378 $this->root->write($this);
379
380 $result='';
381 foreach($this->buffer->array as $v) {
382 $result.=$v->getText();
383 }
384 return $result;
385 }
386 public function write($text, $v1=NULL, $v2=NULL, $v3=NULL, $v4=NULL, $v5=NULL) {
387 global $irp;
388
389 if ( !isset($text) || strlen($text) === 0 ) {
390 return;
391 }
392
393 $text=$irp->Utils->format($text, $v1, $v2, $v3, $v4, $v5);
394
395 $v=NULL;
396 $new=$this->buffer->isEmpty();
397 if(!$new) {
398 $v=$this->buffer->peek();
399 if(!$v->isBufferText()) {
400 $new=TRUE;
401 }
402 }
403
404 if($new) {
405 $v=new IRP_BufferText();
406 $this->buffer->push($v);
407 }
408 $v->appendText($text);
409 }
410 public function writeRelatedBoxIfNeeded() {
411 $result=FALSE;
412 //write the box at the end of the tag only if this is not an <Hn> tag
413 if($this->isWriteRelatedBox()) {
414 $result=$this->writeRelatedBox();
415 }
416 return $result;
417 }
418 public function writeRelatedBox($forceBox=FALSE) {
419 global $irp;
420
421 $written=$irp->Options->getRewriteBoxesWritten();
422 $max=$irp->Options->getRewriteBoxesCount();
423 if(!$forceBox && $written>=$max) {
424 $irp->Log->error('MAX BOX=%s REACHED', $max);
425 return FALSE;
426 }
427
428 $irp->Log->debug('WRITING BOX=%s/%s', $written+1, $max);
429 $result=FALSE;
430 $count=1;//$irp->Options->getRewritePostsInBoxCount();
431 $ids=$irp->Options->getToShowPostsIds($count, TRUE);
432
433 $comment="INLINE RELATED POSTS %s/%s";
434 $comment=sprintf($comment, $written+1, $max);
435 $options=array(
436 'comment'=>$comment
437 , 'shortcode'=>FALSE
438 );
439 $options['includeCss'] = ! $irp->Options->isDoNotIncludeCssInBox();
440 $box=irp_ui_get_box($ids, $options);
441 if($box!='') {
442 $this->pushRelatedBox($box);
443 $result=TRUE;
444 } else {
445 $result=FALSE;
446 $irp->Log->error('NO BOX TO WRITE WITH IDS=%s', $ids);
447 }
448 return $result;
449 }
450 //append related-box element to buffer
451 public function pushRelatedBox($box) {
452 global $irp;
453
454 $v=new IRP_BufferBox();
455 $v->appendText($box);
456 $v->currentBoxWords=$this->currentWords;
457 $v->previousBoxWords=$this->lastBoxWords;
458 $this->buffer->push($v);
459
460 $written=$irp->Options->getRewriteBoxesWritten()+1;
461 $irp->Options->setRewriteBoxesWritten($written);
462 $this->lastBoxWords=$v->currentBoxWords;
463 }
464 //remove related-box elements from buffer starting from the end
465 public function popRelatedBox($args=NULL) {
466 global $irp;
467 if($this->buffer->isEmpty()) {
468 return FALSE;
469 }
470
471 $result=FALSE;
472 $defaults=array('last'=>TRUE, 'all'=>FALSE);
473 $args=$irp->Utils->parseArgs($args, $defaults);
474 if($args['last']) {
475 $v=$this->buffer->peek();
476 if($v->isBufferBox()) {
477 $v=$this->buffer->pop();
478 $this->lastBoxWords=$v->previousBoxWords;
479 $result=TRUE;
480
481 $w=$irp->Options->getRewriteBoxesWritten()-1;
482 $irp->Options->setRewriteBoxesWritten($w);
483 }
484 } elseif($args['all']) {
485 $array=array();
486 for($i=0; $i<count($this->buffer->array); $i++) {
487 $v=$this->buffer->array[$i];
488 if($v->isBufferBox()) {
489 $result=TRUE;
490 } else {
491 $array[]=$v;
492 }
493 }
494 $this->buffer->array=$array;
495 $this->lastBoxWords=0;
496 $irp->Options->setRewriteBoxesWritten(0);
497 }
498 return $result;
499 }
500 public function incCounters($text){
501 global $irp;
502 if($this->skipWordsCount) {
503 return;
504 }
505
506 $text=trim($text);
507 $words=explode(' ', $text);
508 $c=0;
509 foreach($words as $w) {
510 $w=trim($w);
511 if($w!='' && strlen($w)>1) {
512 $c++;
513 }
514 }
515
516 $this->currentWords+=$c;
517 $irp->Log->debug('TEXT=[%s] INCREMENT WORDS words[%s]/currentWords[%s]'
518 , $text, $c, $this->currentWords);
519 }
520 }
521
522 class IRP_BufferElement {
523 var $text;
524 public function __construct() {
525 $this->text='';
526 }
527
528 public function getText() {
529 return $this->text;
530 }
531 public function appendText($text) {
532 $this->text.=$text;
533 }
534
535 public function isBufferBox() {
536 return FALSE;
537 }
538 public function isBufferText() {
539 return FALSE;
540 }
541 }
542 class IRP_BufferText extends IRP_BufferElement {
543 public function __construct() {
544 parent::__construct();
545 }
546
547 public function isBufferBox() {
548 return FALSE;
549 }
550 public function isBufferText() {
551 return TRUE;
552 }
553 }
554 class IRP_BufferBox extends IRP_BufferElement {
555 var $currentBoxWords;
556 var $previousBoxWords;
557
558 public function __construct() {
559 parent::__construct();
560 $this->currentBoxWords=0;
561 $this->previousBoxWords=0;
562 }
563
564 public function isBufferBox() {
565 return TRUE;
566 }
567 public function isBufferText() {
568 return FALSE;
569 }
570 }