Your IP : 216.73.216.240
<?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;
}
}