| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace kalanis\kw_forums\Cutting; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  * Class CuttingContent | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  * @package kalanis\kw_forums\Cutting | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  * Cutting messages | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | class Content | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |     // it's necessary to have both arrays sorted this way - it's for lookup by positions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |     /** @var string[] */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |     protected static array $OPENING_TAGS = ['<b ',  '<b>',  '<i ',  '<i>',  '<u ',  '<u>',  '<center>',  '<span>',  '<span ',  '<font color', '<font face', '<font size', '<font ', '<font', '<table ', '<table', '<tr>', '<td>', '<a ', '<a>']; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |     /** @var string[] */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     protected static array $CLOSING_TAGS = ['</b>', '</b>', '</i>', '</i>', '</u>', '</u>', '</center>', '</span>', '</span>', '</font>', '</font>', '</font>', '</font>', '</font>', '</table>', '</table>', '</tr>', '</td>', '</a>', '</a>']; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     protected int $wordLengthNeedle = 20; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |     protected int $maxLength = 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |     protected string $content = ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |      * Contains positions of tags in | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |      * @var int[] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |     protected array $tagPositionsStack = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 | 6 |  |     public function __construct(int $maxLength) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 | 6 |  |         $this->maxLength = $maxLength; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 | 6 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 | 6 |  |     public function setContent(string $content): self | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 | 6 |  |         $this->content = $content; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 | 6 |  |         $this->tagPositionsStack = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 | 6 |  |         return $this; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 40 | 6 |  |     public function getContent(): string | 
            
                                                                        
                            
            
                                    
            
            
                | 41 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 42 | 6 |  |         return $this->content; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 | 6 |  |     public function process(): self | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 | 6 |  |         if (mb_strlen($this->content) <= $this->maxLength) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 | 1 |  |             return $this; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         // lookup for available end, the values has been found empirically | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 | 5 |  |         $content = mb_substr($this->content, 0, $this->maxLength + $this->wordLengthNeedle); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 | 5 |  |         $len = mb_strrpos($content, ' '); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 5 |  |         $len = false !== $len ? intval($len) : null; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 | 5 |  |         $content = mb_substr($content, 0, $len) . ' '; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 | 5 |  |         $this->content = $this->closeQuotationMarks($this->contentCut($content)) . $this->fillCutTags() . ' ...'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 | 5 |  |         return $this; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |      * @param string $content content to cut | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |      * @return string updated string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 | 5 |  |     protected function contentCut(string $content): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 | 5 |  |         $this->tagPositionsStack = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 | 5 |  |         for ($i = 0; $i <= mb_strlen($content); $i++) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |             // start tag sequence | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 | 5 |  |             if ('<' == mb_substr($content, $i, 1)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  | //print_r(['found open', $i]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 | 4 |  |                 if ('/' == mb_substr($content, $i + 1, 1)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |                     // closing tag | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 | 1 |  |                     $tagPosition = $this->tagPosition(mb_strtolower(mb_substr($content, $i, 7)), static::$CLOSING_TAGS); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 | 1 |  |                     if (!is_null($tagPosition)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |                         // is correct one in array of closing tags? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 | 1 |  |                         $lastPosition = array_pop($this->tagPositionsStack); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 | 1 |  |                         if (!is_null($lastPosition)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 | 1 |  |                             if (static::$CLOSING_TAGS[$tagPosition] == static::$CLOSING_TAGS[$lastPosition]) { // because there are multiple openings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 | 1 |  |                                 $i = $i + mb_strlen(static::$CLOSING_TAGS[$tagPosition]) - 2; // move to next available position in string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |                             } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 | 1 |  |                                 $this->tagPositionsStack[] = $lastPosition; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |                             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |                         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  | //print_r(['is closing', $tagPosition, is_null($tagPosition) ? 'x' : static::$CLOSING_TAGS[$tagPosition]]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |                 } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |                     // opening tag | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |                     // cut by longest available tag in array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 4 |  |                     $tagPosition = $this->tagPosition(mb_substr($content, $i, 11), static::$OPENING_TAGS); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 | 4 |  |                     if (!is_null($tagPosition)) { // is as pair in array and I know that | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 4 |  |                         $this->tagPositionsStack[] = $tagPosition; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 | 4 |  |                         $i = $i + mb_strlen(static::$OPENING_TAGS[$tagPosition]) - 1; // move to next available position in string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |                     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  | //print_r(['is opening', $tagPosition, is_null($tagPosition) ? 'x' : static::$OPENING_TAGS[$tagPosition]]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |                 } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 | 5 |  |         return $content; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |      * Returns tag position | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |      * @param string $lookupTag | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |      * @param string[] $definedTags | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |      * @return int|null | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |      * int as position in defined tags, null as not found | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 | 4 |  |     protected function tagPosition(string $lookupTag, array $definedTags): ?int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 | 4 |  |         foreach ($definedTags as $position => $definedTag) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 4 |  |             $cutTag = mb_substr($lookupTag, 0, mb_strlen($definedTag)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 | 4 |  |             if ($cutTag == $definedTag) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 | 4 |  |                 return $position; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 | 2 |  |         return null; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 | 5 |  |     protected function closeQuotationMarks(string $content): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         // check for closing tags with spaces and quotation marks inside | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 5 |  |         $tagStarts = mb_strrpos($content, '<'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 | 5 |  |         $tagEnds = mb_strrpos($content, '>'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 | 5 |  |         if ((false !== $tagStarts) && ((false === $tagEnds) || (false !== $tagEnds) && ($tagStarts > $tagEnds))) { // unclosed tag | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 | 3 |  |             $foundOdd = mb_substr_count(mb_substr($content, $tagStarts), "'"); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 | 3 |  |             if ($foundOdd % 2) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 | 1 |  |                 $content .= "'"; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 | 3 |  |             $foundOdd = mb_substr_count(mb_substr($content, $tagStarts), '"'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 | 3 |  |             if ($foundOdd % 2) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 | 1 |  |                 $content .= '"'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 | 3 |  |             $content .= '>'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 | 5 |  |         return $content; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 | 5 |  |     protected function fillCutTags(): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  | //var_dump(['rev', $this->tagPositionsStack]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 | 5 |  |         $content = ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 | 5 |  |         foreach (array_reverse($this->tagPositionsStack) as $positions) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 | 4 |  |             $content .= static::$CLOSING_TAGS[$positions]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 | 5 |  |         return $content; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 150 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 151 |  |  |  |