223 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace XFramework;
 | 
						|
 | 
						|
/**
 | 
						|
 * Roundcube Plus Framework plugin.
 | 
						|
 *
 | 
						|
 * Copyright 2017, Tecorama LLC.
 | 
						|
 *
 | 
						|
 * @license Commercial. See the LICENSE file for details.
 | 
						|
 */
 | 
						|
 | 
						|
require_once "Singleton.php";
 | 
						|
 | 
						|
class Html
 | 
						|
{
 | 
						|
    use Singleton;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $marker
 | 
						|
     * @param string $insertString
 | 
						|
     * @param string $html
 | 
						|
     * @param string $container
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function insertBefore(string $marker, string $insertString, string &$html, string $container = ""): bool
 | 
						|
    {
 | 
						|
        if ($pos = $this->findStart($container, $marker, $html, false)) {
 | 
						|
            $html = substr_replace($html, $insertString, $pos, 0);
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $marker
 | 
						|
     * @param string $tagName
 | 
						|
     * @param string $insertString
 | 
						|
     * @param string $html
 | 
						|
     * @param string $container
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function insertAfter(string $marker, string $tagName, string $insertString, string &$html, string $container = ""): bool
 | 
						|
    {
 | 
						|
        if ($pos = $this->findEnd($container, $marker, $tagName, $html)) {
 | 
						|
            $html = substr_replace($html, $insertString, $pos, 0);
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $marker
 | 
						|
     * @param string $insertString
 | 
						|
     * @param string $html
 | 
						|
     * @param string $container
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function insertAtBeginning(string $marker, string $insertString, string &$html, string $container = ""): bool
 | 
						|
    {
 | 
						|
        if ($pos = $this->findStart($container, $marker, $html, true)) {
 | 
						|
            $html = substr_replace($html, $insertString, $pos, 0);
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $marker - String to search for, it can be a class or id within a tag or a text within a tag. The function
 | 
						|
     *        will search for the first tag to the left of the marker to identify the element at the end of which the
 | 
						|
     *        text should be inserted.
 | 
						|
     * @param string $insertString - String to insert before the closing tag.
 | 
						|
     * @param string $html - Html code to modify.
 | 
						|
     * @return bool - True if the string has been successfully inserted, false otherwise.
 | 
						|
     */
 | 
						|
    public function insertAtEnd(string $marker, string $insertString, string &$html): bool
 | 
						|
    {
 | 
						|
        // find marker
 | 
						|
        if (!($i = stripos($html, $marker))) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // get the html element
 | 
						|
        if (!($i = strripos(substr($html, 0, $i), "<")) || !($j = stripos($html, " ", $i))) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $tag = substr($html, $i + 1, $j - $i - 1);
 | 
						|
        $count = 0;
 | 
						|
 | 
						|
        do {
 | 
						|
            if (($c = stripos($html, "</$tag>", $i)) === false) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            if (($n = stripos($html, "<$tag ", $i)) === false) {
 | 
						|
                $n = $c + 1;
 | 
						|
            }
 | 
						|
 | 
						|
            if ($c > $n) {
 | 
						|
                $count++;
 | 
						|
                $i = $n + 1;
 | 
						|
            } else {
 | 
						|
                $count--;
 | 
						|
                $i = $c + 1;
 | 
						|
            }
 | 
						|
        } while ($count);
 | 
						|
 | 
						|
        $html = substr_replace($html, $insertString, $i - 1, 0);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $insertString
 | 
						|
     * @param string $html
 | 
						|
     * WARNING: Don't use this to insert html because it causes Roundcube to re-order script tag positioning and some plugins
 | 
						|
     * that insert their code at the end of the page might not get the scripts they expect (for example, Thunderbird labels.)
 | 
						|
     */
 | 
						|
    public function insertBeforeBodyEnd(string $insertString, string &$html)
 | 
						|
    {
 | 
						|
        $html = str_replace("</body>", $insertString . "</body>", $html);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $insertString
 | 
						|
     * @param string $html
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function insertAfterBodyStart(string $insertString, string &$html): bool
 | 
						|
    {
 | 
						|
        if (($i = strpos($html, "<body ")) !== false &&
 | 
						|
            ($j = strpos($html, ">", $i + 1))
 | 
						|
        ) {
 | 
						|
            $html = substr_replace($html, "\n" . $insertString, $j + 1, 0);
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $insertString
 | 
						|
     * @param string $html
 | 
						|
     */
 | 
						|
    public function insertBeforeHeadEnd(string $insertString, string &$html)
 | 
						|
    {
 | 
						|
        $html = str_replace("</head>", $insertString . "</head>", $html);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $container
 | 
						|
     * @param string $marker
 | 
						|
     * @param string $html
 | 
						|
     * @param bool $inner
 | 
						|
     * @return bool|int
 | 
						|
     */
 | 
						|
    private function findStart(string $container, string $marker, string $html, bool $inner)
 | 
						|
    {
 | 
						|
        if (!($pos = $this->findMarker($container, $marker, $html))) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($inner) {
 | 
						|
            if (substr($marker, -1, 1) != ">") {
 | 
						|
                $pos = strpos($html, ">", $pos);
 | 
						|
                if ($pos) {
 | 
						|
                    $pos++;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            // if marker doesn't include the opening tag name, find the beginning of the tag
 | 
						|
            if (strpos($marker, "<") !== 0) {
 | 
						|
                $pos = strrpos(substr($html, 0, $pos + 1), "<");
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $pos;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $container
 | 
						|
     * @param string $marker
 | 
						|
     * @param string $tagName
 | 
						|
     * @param string $html
 | 
						|
     * @return bool|int
 | 
						|
     */
 | 
						|
    private function findEnd(string $container, string $marker, string $tagName, string $html)
 | 
						|
    {
 | 
						|
        if (!($pos = $this->findMarker($container, $marker, $html))) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // find the closing tag
 | 
						|
        $end = $pos;
 | 
						|
 | 
						|
        do {
 | 
						|
            $innerTagStart = strpos($html, "<$tagName ", $end + 1);
 | 
						|
            $end = strpos($html, "</$tagName>", $end + 1);
 | 
						|
        } while ($end !== false && $innerTagStart !== false && $innerTagStart < $end);
 | 
						|
 | 
						|
        return $end + strlen("</$tagName>");
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $container
 | 
						|
     * @param string $marker
 | 
						|
     * @param string $html
 | 
						|
     * @return bool|int
 | 
						|
     */
 | 
						|
    private function findMarker(string $container, string $marker, string $html)
 | 
						|
    {
 | 
						|
        $start = empty($container) ? strpos($html, "<body ") : strpos($html, $container);
 | 
						|
 | 
						|
        if ($start === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        return strpos($html, $marker, $start);
 | 
						|
    }
 | 
						|
} |