Your IP : 216.73.216.240


Current Path : /home/juvelize/saulnois/tmp/install_695d2cf0b4957/src/
Upload File :
Current File : /home/juvelize/saulnois/tmp/install_695d2cf0b4957/src/TDom.php

<?php
/*
* @package		Tech Fry Library
* @license		https://www.gnu.org/licenses/gpl-3.0.en.html
*/

namespace TechFry\Library;

defined('_JEXEC') or die;

// Class for handling HTML and XML
class TDom extends THelper
{
    public $dom;
    
    public $code;

    public function __construct($code = '', $source_type = 'html')
    {
        $this->dom = new \DOMDocument;

        $this->code = $code;

        if ($code)
        {
            if ($source_type == 'html')
            {
                $code = htmlspecialchars_decode(htmlentities($code));
            
                // LIBXML_HTML_NOIMPLIED - turns off the automatic adding of implied html/body elements
                // LIBXML_HTML_NODEFDTD - prevents a default doctype being added
                // The @ suppresses warnings and errors

                $dom->preserveWhiteSpace = false;
                @$dom->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
            }
            else
            {
                $this->dom->loadXML($code);
            }
        }
    }
    
    public static function get_dom($code, $source_type = 'html')
    {
        $dom = new \DOMDocument;

        if ($source_type == 'html')
        {
        	// $code = mb_convert_encoding($code, 'HTML-ENTITIES', 'UTF-8'); // Depreciated
            $code = htmlspecialchars_decode(htmlentities($code));
        
            // LIBXML_HTML_NOIMPLIED - turns off the automatic adding of implied html/body elements
            // LIBXML_HTML_NODEFDTD - prevents a default doctype being added

        	$dom->preserveWhiteSpace = false;
        	@$dom->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        }
        elseif ($source_type == 'xml')
        {
            $dom->loadXML($code);
        }

        return $dom;
    }

    // 02. Get array of HTML elements
    public function get_html($config = [])
    {
        $tag = $config['tag'];
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $content = $config['content'] ?? '';
        $relation = $config['relation'] ?? '';

        $xpath = new \DOMXpath($this->dom);
        $q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);

        $elements = $xpath->query($q); // DOMNodeList
        if ($elements->length == 0)
        {
            return false;
        }

        foreach ($elements as $node)
        {
            // $node - DOMElement or DOMNode
            if (!$relation)
            {
                $html_arr[] = $dom->saveHTML($node);
            }
            else
            {
                $html_arr[] = $dom->saveHTML($node->$relation);
            }
        }

        return $html_arr;
    }

    // 03. Get array of element content
    public function get_content($config = [])
    {
        $tag = $config['tag'];
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $content = $config['content'] ?? '';
        $relation = $config['relation'] ?? '';
        
        $xpath = new \DOMXpath($this->dom);
        $q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);

        $elements = $xpath->query($q);
        if ($elements->length == 0)
        {
            return false;
        }

        foreach ($elements as $node)
        {
            if (!$relation)
            {
                $values[] = $node->textContent;
            }
            else
            {
                $values[] = $node->$relation->textContent;
            }
        }

        return $values;
    }

    // 04. Get array of attribute values
    public function get_attr($config = [])
    {
        $tag = $config['tag'];
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $content = $config['content'] ?? '';
        $relation = $config['relation'] ?? '';

        $target = $config['target_attr'];

        $xpath = new \DOMXpath($this->dom);
        $q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);

        $elements = $xpath->query($q);
        if ($elements->length == 0)
        {
            return false;
        }

        foreach ($elements as $node)
        {
            if (!$relation)
            {
                $attr_values[] = $node->getAttribute($target);
            }
            else
            {
                $attr_values[] = $node->$relation->getAttribute($target);
            }
        }

        return $attr_values;
    }

    // 05. Add attribute value
    public function add_attr($config = [])
    {
        $tag = $config['tag'];
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        
        $elements = $this->dom->getElementsByTagName($tag);

        if (\is_array($attr_value))
        {
            foreach ($elements as $k => $node)
            {
                $node->setAttribute($attr_name, $attr_value[$k]);
            }
        }
        else
        {
            foreach ($elements as $node)
            {
                $node->setAttribute($attr_name, $attr_value);
            }
        }

        return $dom->saveHTML();
    }

    // 06. Remove all attributes from HTML except some
    public function rem_attr($noremove = [])
    {
        $xpath = new \DOMXPath($this->dom);
        $elements = $xpath->query('//@*');

        foreach ($elements as $node)
        {
            if (!in_array($node->nodeName, $noremove))
            {
                $node->parentNode->removeAttribute($node->nodeName);
            }
        }

        return $dom->saveHTML();
    }

    // 07. Remove complete element from html code
    public function rem_element($config = [])
    {
        $tag = $config['tag'];
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $content = $config['content'] ?? '';

        $xpath = new \DOMXpath($this->dom);
        $q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);
        
        $elements = $xpath->query($q);
        if ($elements->length == 0)
        {
            return $html;
        }
        
        foreach ($elements as $node)
        {
            $node->remove();
        }
        
        return $this->dom->saveHTML();
    }

    // 08. Scan - Return array of all tag names in html or xml
    public function get_all_tags()
    {
        $xpath = new \DOMXpath($this->dom);
        $elements = $xpath->query('//*');

        $tag_names[] = [];

        foreach ($elements as $k => $node)
        {
            // $node->nodeType; // 1 for DOMElement, 2 for DOMAttr, 3 for DOMText
            // $node->parentNode, $node->parentElement
            // $node->childNodes,
            
            $tag_names[$k]['tag_name'] = $node->tagName;
            $tag_names[$k]['id'] = $node->getAttribute('id') ?? '';
            $tag_names[$k]['class'] = $node->getAttribute('class') ?? '';
            $tag_names[$k]['total_children'] = $node->childElementCount;
        }

        return $tag_names;
    }

    // 09. Scan for specific html or xml tag
    public function tag_scan($config = [])
    {
        $tag = $config['tag'];
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $content = $config['content'] ?? '';

        $xpath = new \DOMXpath($this->dom);
        $q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);

        $elements = $xpath->query($q);

        $info[] = [];

        foreach ($elements as $i => $node)
        {
            if ($node->attributes->length)
            {
                $info[$i]['attributes'] = $node->attributes->length;
                for ($num = 0; $num < $node->attributes->length; $num++)
                {
                    $info[$i]['attr_names'] .= '<small>';
                    $info[$i]['attr_names'] .= $node->attributes->item($num)->nodeName . '=' . $node->attributes->item($num)->nodeValue . '<br>';
                    $info[$i]['attr_names'] .= '</small>';
                }
            }
            else
            {
                $info[$i]['attributes'] = 0;
                $info[$i]['attr_names'] = '';
            }

            $info[$i]['parent'] = $node->parentNode->tagName;
            $info[$i]['node_value'] = '<small>' . substr($node->nodeValue, 0, 200) . '</small>';
        }

        return $info;
    }

    // 10. Scan for specific attribute
    public function attr_scan()
    {
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';

        $xpath = new \DOMXpath($this->dom);
      	$q = '//' . $tag;

        if ($attr_name)
        {
            $q .= '//@' . $attr_name;
            if ($attr_value)
            {
                $q .= '="' . $attr_value . '"';
            }
            $q .= ']';
        }

        $elements = $xpath->query($q);

        $info[] = [];

        foreach ($elements as $i => $node)
        {
            $info[$i]['tag'] = $node->ownerElement->tagName;
          	$info[$i]['value'] = $node->nodeValue;
          	$info[$i]['node_path'] = $node->getNodePath();
        }

        return $info;
    }

    // 11. Get array of attribute values as associative array
    public function get_smart_attr($code, $tag, $value_attr, $key_attr = '', $source_type = 'html')
    {
        $tag = $config['tag'];

        $xpath = new \DOMXpath($this->dom);
        $q = '//' . $tag;

        $elements = $xpath->query($q);
        if ($elements->length == 0)
        {
            return false;
        }

        foreach ($elements as $node)
        {
            $key_name = $node->getAttribute($key_attr);
            if ($key_name)
            {
                $key_name = preg_replace('/[^A-Za-z_]/', '_', $key_name);
                $attr_values[$key_name] = $node->getAttribute($value_attr);
            }
        }

        return $attr_values;
    }

    public function get_xpath_query($tag, $attribute = [], $content = '')
    {
        // Refer: https://www.php.net/manual/en/domxpath.query.php

        // root, tags (nodes), attributes, values, combination of tags attributes & values
        /*
            /node	Root of the document
            //node	Anywhere in the document
            *	wildcard can be used instead of node name
            [@attribute="value"]
            [n]	select n-th node (starts at 1)
            .   Current node
            ..	Parent of current node
            preceding::	selects all preceding nodes (above)
            following::	selects all following nodes (below)
            preceding-sibling::	selects preceding siblings (above)
            following-sibling::	selects following siblings (below)
            a[contains(text(), "social")]
            //a[starts-with(text(), "social")]
            //a[ends-with(text(), "Twitter")]
            //p[string-length(text())>10]
            
            @attribute	selects attribute by name (DOMAttr)
            text() (DOMText)
        */

        // All nodes of tag
        $q = '//' . $tag;

        // Filter by attribute
        if (isset($attribute[0]) && $attribute[0])
        {
            $attr .= $attribute[0];
            if (isset($attribute[1]) && $attribute[1] != '')
            {
                $first_char = substr($attribute[1], 0, 1);
                switch ($firstChar) 
                {
                    case '^':
                        $val = substr($value, 1);
                        $q .= = "starts-with(@$attr, '$val')";
                        break;

                    case '~':
                        $val = substr($value, 1);
                        $q .= = "contains(@$attr, '$val')";
                        break;

                    case '$':
                        $val = substr($value, 1);
                        $q .= = "substring(@$attr, string-length(@$attr) - " . (strlen($val) - 1) . ") = '$val'";
                        break;
                        
                    default:
                        $q .= = "@$attr='$value'";
                        break;
                }
            }
            else
            {
                $q .= '[@' . $attribute[0];
            }
            $q .= ']';
        }

        // Filter by content value
        if ($content != '')
        {
            $first_char = substr($content, 0, 1);

            switch ($firstChar) 
            {
                case '^':
                    $val = substr($content, 1);
                    $q .= = "starts-with(text(), '$val')";
                    break;

                case '~':
                    $val = substr($content, 1);
                    $q .= "contains(text(), '$val')";
                    break;

                case '$':
                    $val = substr($content, 1);
                    $q .= = "substring(text(), string-length(text()) - " . (strlen($val) - 1) . ") = '$val'";
                    break;

                default:
                    $q .= "text()='$content'";
                    break;
            }
        }

        return $q;
    }
}