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/TfDom.php

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

namespace TechFry\Library;

defined('_JEXEC') or die;

use Joomla\CMS\Factory;

class TfDom
{
    // 01. Refer: https://www.php.net/manual/en/class.domdocument.php
    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 static function get_html2($html, $config = array())
    {
        $source_type = $config['source_type'] ?? 'html';
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $elem_value = $config['elem_value'] ?? '';
        $relation = $config['relation'] ?? '';

        $dom = self::get_dom($html, $source_type);

        $xpath = new \DOMXpath($dom);
        $q = self::get_xpath_query($config['tag'], array($attr_name, $attr_value), $elem_value);

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

        foreach ($contents as $content)
        {
            // $content - DOMElement
            if (!$relation)
            {
                $html_arr[] = $dom->saveHTML($content);
            }
            else
            {
                $html_arr[] = $dom->saveHTML($content->$relation);
            }
        }

        return $html_arr;
    }

    // 03. Get array of element values
    public static function get_value2($html, $config = array())
    {
        $source_type = $config['source_type'] ?? 'html';
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $elem_value = $config['elem_value'] ?? '';
        $relation = $config['relation'] ?? '';
        
        $dom = self::get_dom($html, $source_type);
        
        $xpath = new \DOMXpath($dom);
        $q = self::get_xpath_query($config['tag'], array($attr_name, $attr_value), $elem_value);

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

        foreach ($contents as $content)
        {
            if (!$relation)
            {
                $values[] = $content->nodeValue;
            }
            else
            {
                $values[] = $content->$relation->nodeValue;
            }
        }

        return $values;
    }

    // 04. Get array of attribute values
    public static function get_attr2($html, $config = array())
    {
        if (!$html)
        {
            return;
        }
        
        $source_type = $config['source_type'] ?? 'html';
        $attr_name = $config['attr_name'] ?? '';
        $attr_value = $config['attr_value'] ?? '';
        $elem_value = $config['elem_value'] ?? '';
        $relation = $config['relation'] ?? '';
        $target = $config['target_attr'];
        
        $dom = self::get_dom($html, $source_type);

        $xpath = new \DOMXpath($dom);
        $q = self::get_xpath_query($config['tag'], array($attr_name, $attr_value), $elem_value);

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

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

        return $attr_values;
    }

    // 05. Add attribute to specific tag
    public static function add_attr($html, $tag, $attr, $attr_value)
    {
        $dom = self::get_dom($html);

        $nodes = $dom->getElementsByTagName($tag);

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

        return $dom->saveHTML();
    }

    // 06. Remove all attributes from HTML except some
    public static function rem_attr($html, $noremove = array())
    {
        $dom = self::get_dom($html);

        $xpath = new \DOMXPath($dom);
        $nodes = $xpath->query('//@*');

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

        return $dom->saveHTML();
    }

    // 07. Remove complete element from html code
    public static function rem_element($html, $tag, $attr_name = '', $attr_value = '', $elem_value = '')
    {
        $dom = self::get_dom($html);

        $xpath = new \DOMXpath($dom);
        $q = self::get_xpath_query($tag, array($attr_name, $attr_value), $elem_value);
        
        $contents = $xpath->query($q);

        if ($contents->length == 0)
        {
            return $html;
        }
        
        foreach ($contents as $content)
        {
            $content->remove();
        }
        
        return $dom->saveHTML();
    }

    // 08. Scan - Return array of tag names in html or xml
    public static function get_tags($code, $source_type = 'html')
    {
        $dom = self::get_dom($code, $source_type);

        $xpath = new \DOMXpath($dom);
        $elements = $xpath->query('//*');

        Factory::getApplication()->enqueueMessage('Length: ' . $elements->length);

        $tag_names[] = array();

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

        return $tag_names;
    }

    // 09. Scan for specific html or xml tag
    public static function tag_scan($code, $tag, $attr_name = '', $attr_value = '', $value = '', $source_type = 'html')
    {
        $dom = self::get_dom($code, $source_type);

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

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

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

        Factory::getApplication()->enqueueMessage('XPath: ' . $q);

        $info[] = array();

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

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

        return $info;
    }

    // 10. 
    public static function attr_scan($code, $attr_name, $attr_value = '', $source_type = 'html')
    {
        $dom = self::get_dom($code, $source_type);

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

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

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

        Factory::getApplication()->enqueueMessage('XPath: ' . $q);

        $info[] = array();

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

        return $info;
    }

    // 11. Get array of attribute values as associative array
    public static function get_smart_attr($code, $tag, $value_attr, $key_attr = '', $source_type = 'html')
    {
        $dom = self::get_dom($code, $source_type);

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

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

        if ($contents->length == 0)
        {
            return false;
        }

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

        return $attr_values;
    }

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

        // root, tags (nodes), attributes, values, combination of tags attributes & values
        /*
            /node	selects a direct child that matches node name.
            //node	selects any descendant - child, grandchild, gran-grandchild etc.
            *	wildcard can be used instead of node name
            [@attribute="value"]
            [n]	select n-th node (starts at 1)
            ..	selects element parent
            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)
        */

        $q = '//' . $tag;
        if (isset($attribute[0]) && $attribute[0])
        {
            $q .= '[@' . $attribute[0];
            if (isset($attribute[1]) && $attribute[1])
            {
                $q .= '="' . $attribute[1] . '"';
            }
            $q .= ']';
        }

        if ($value)
        {
            $q .= '[contains(text(), "' . $value . '")]';
        }

        return $q;
    }

    // Get array of HTML elements (Depreciated: Use v2)
    public static function get_html($html, $tag, $attr_name = '', $attr_value = '', $elem_value = '', $source_type = 'html')
    {
        $dom = self::get_dom($html, $source_type);

        $xpath = new \DOMXpath($dom);
        $q = self::get_xpath_query($tag, array($attr_name, $attr_value), $elem_value);

        $contents = $xpath->query($q); // DOMNodeList

        if ($contents->length == 0)
        {
            return false;
        }

        foreach ($contents as $content)
        {
            echo $content->nextElementSibling->nodeValue;
        }

        return $html_arr;
    }

    // Get array of element values (Depreciated: use v2)
    public static function get_value($code, $tag, $attr_name = '', $attr_value = '', $elem_value = '', $source_type = 'html')
    {
        $dom = self::get_dom($code, $source_type);
        
        $xpath = new \DOMXpath($dom);
        $q = self::get_xpath_query($tag, array($attr_name, $attr_value), $elem_value);

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

        foreach ($contents as $content)
        {
            $values[] = $content->nodeValue;
        }

        return $values;
    }

    // Get array of attribute values (Depreciated: use v2)
    public static function get_attr($code, $tag, $target, $attr_name = '', $attr_value = '', $elem_value = '', $source_type = 'html')
    {
        $dom = self::get_dom($code, $source_type);

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

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

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

        if ($contents->length == 0)
        {
            return false;
        }

        foreach ($contents as $content)
        {
            if (!$elem_value || strpos($content->nodeValue, $elem_value) !== false)
            {
                $attr_values[] = $content->getAttribute($target);
            }
        }

        return $attr_values;
    }
}