shell bypass 403
<?php
namespace WPDaddy\Dom;
use DateTime;
use DOMAttr;
use DOMDocument;
use DOMElement;
/**
* The most general base class from which all objects in a Document inherit.
*
* @property-read Attr[] $attributes
* @property string $className Gets and sets the value of the class attribute
* @property-read TokenList $classList Returns a live TokenList collection of
* the class attributes of the element
* @property bool $checked Indicates whether the element is checked or not
* @property bool $selected Indicates whether the element is selected or not
* @property string $value Gets or sets the value of the element according to
* its element type
* @property string $id Gets or sets the value of the id attribute
* @property string $innerHTML Gets or sets the HTML syntax describing the
* element's descendants
* @property string $outerHTML Gets or sets the HTML syntax describing the
* element and its descendants. It can be set to replace the element with nodes
* parsed from the given string
* @property string $innerText
* @property-read StringMap $dataset
*
* @property string accept
* @property string acceptCharset
* @property string accessKey
* @property string action
* @property bool async
* @property bool autofocus
* @property bool autoplay
* @property string alt
* @property bool autocapitalize
* @property bool autocomplete
* @property string charset
* @property string cite
* @property string cols
* @property bool contentEditable
* @property bool controls
* @property string data
* @property string dateTime
* @property bool defer
* @property bool disabled
* @property string dir
* @property bool draggable
* @property string download
* @property string encoding
* @property string enctype
* @property string form
* @property string height
* @property string high
* @property string htmlFor
* @property string href
* @property string kind
* @property string label
* @property string lang
* @property bool loop
* @property string low
* @property string min
* @property string max
* @property string maxLength
* @property string mediaGroup
* @property bool multiple
* @property bool muted
* @property string name
* @property bool optimum
* @property string pattern
* @property string placeholder
* @property string poster
* @property bool preload
* @property string readOnly
* @property string rel
* @property bool reversed
* @property bool required
* @property string rows
* @property string start
* @property string step
* @property string style
* @property string size
* @property string span
* @property string src
* @property string srcset
* @property string tabindex
* @property string target
* @property string title
* @property string type
* @property string width
* @property string wrap
*
* @method Attr setAttribute(string $name, string $value)
* @method Attr setAttributeNode(DOMAttr $attr)
* @method Attr getAttributeNode(string $name)
*/
class Element extends DOMElement {
use LiveProperty, NonDocumentTypeChildNode, ChildNode, ParentNode;
const VALUE_ELEMENTS = [ "BUTTON", "INPUT", "METER", "OPTION", "PROGRESS", "PARAM" ];
/** @var TokenList */
protected $liveProperty_classList;
/** @var StringMap */
protected $liveProperty_dataset;
/** @var ?DateTime */
protected $liveProperty_valueAsDate;
/** @var ?float */
protected $liveProperty_valueAsNumber;
/**
* @const Array
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement#Elements_that_are_considered_form_controls
*/
const FORM_CONTROL_ELEMENTS = [ 'button', 'fieldset', 'input', 'object', 'output', 'select', 'textarea' ];
/**
* returns true if the element would be selected by the specified selector
* string; otherwise, returns false.
*
* @param string $selectors The CSS selector(s) to check against
*
* @return bool True if this element is selectable by provided selector
*/
public function matches($selectors){
$matches = $this->getRootDocument()->querySelectorAll($selectors);
$i = $matches->length;
/** @noinspection PhpStatementHasEmptyBodyInspection */
while(--$i >= 0 && $matches->item($i) !== $this) {
;
}
return ($i >= 0);
}
/**
* Returns a live HTMLCollection containing all child elements which have all
* of the given class names. When called on the document object, the complete
* document is searched, including the root node.
*
* @param string $names a string representing the list of class names to
* match; class names are separated by whitespace
*
* @return HTMLCollection
*/
public function getElementsByClassName($names){
$namesArray = explode(" ", $names);
$dots = ".".implode(".", $namesArray);
return $this->css($dots);
}
/**
* Returns the closest ancestor of the current element (or itself)
* which matches the selectors.
*
* @param string $selectors CSS selector(s)
*
* @return Element|null
*/
public function closest($selectors){
$collection = $this->css($selectors, "ancestor-or-self::");
return $collection->item(count($collection)-1);
}
public function getAttribute($name){
$value = parent::getAttribute($name);
if(strlen($value) === 0) {
return null;
}
return $value;
}
public function prop_get_className(){
return $this->getAttribute("class");
}
/**
* @param string $value
*
* @return void
*/
public function prop_set_className($value){
$this->setAttribute("class", $value);
}
public function prop_get_classList(){
if(!$this->liveProperty_classList) {
$this->liveProperty_classList = new TokenList($this, "class");
}
return $this->liveProperty_classList;
}
public function prop_get_value(){
$methodName = 'value_get_'.$this->tagName;
if(method_exists($this, $methodName)) {
return $this->$methodName();
}
if(in_array(strtoupper($this->tagName), self::VALUE_ELEMENTS)) {
return $this->getAttribute("value");
}
return null;
}
public function prop_set_value($newValue){
$methodName = 'value_set_'.$this->tagName;
if(method_exists($this, $methodName)) {
return $this->$methodName($newValue);
}
$this->setAttribute("value", $newValue);
}
public function prop_get_id(){
return $this->getAttribute("id");
}
public function prop_set_id($newValue){
$this->setAttribute("id", $newValue);
}
public function prop_get_innerHTML(){
$childHtmlArray = [];
foreach($this->childNodes as $child) {
$childHtmlArray [] = $this->ownerDocument->saveHTML($child);
}
return implode(PHP_EOL, $childHtmlArray);
}
public function prop_set_innerHTML($html){
$importDocument = new DOMDocument(
"1.0",
"utf-8"
);
$htmlWrapped = "<!doctype html><html><body>$html</body></html>";
if(function_exists('mb_convert_encoding')) {
$htmlWrapped = mb_convert_encoding(
$htmlWrapped,
"HTML-ENTITIES",
"UTF-8"
);
$importDocument->loadHTML($htmlWrapped);
} else {
$importDocument->loadHTML('<meta http-equiv="content-type" content="text/html; charset=utf-8">'.$htmlWrapped);
}
$importBody = $importDocument->getElementsByTagName(
"body"
)->item(0)
;
$node = $this->ownerDocument->importNode(
$importBody,
true
);
while($this->firstChild) {
$this->removeChild($this->firstChild);
}
$fragment = $this->ownerDocument->createDocumentFragment();
while($node->firstChild) {
$fragment->appendChild($node->firstChild);
}
$this->appendChild($fragment);
}
public function prop_get_outerHTML(){
return $this->ownerDocument->saveHTML($this);
}
public function prop_set_outerHTML($html){
$fragment = $this->ownerDocument->createDocumentFragment();
$fragment->appendXML($html);
$this->replaceWith($fragment);
}
public function prop_get_innerText(){
return $this->textContent;
}
public function prop_set_innerText($value){
$this->textContent = $value;
return $this->textContent;
}
public function prop_get_dataset(){
if(empty($this->liveProperty_dataset)) {
$this->liveProperty_dataset = $this->createDataset();
}
return $this->liveProperty_dataset;
}
public function prop_get_checked(){
return $this->hasAttribute("checked");
}
public function prop_set_checked($checked){
if($checked) {
if($this->getAttribute("type") === "radio") {
// TODO: Use `form` attribute when implemented: https://github.com/PhpGt/Dom/issues/161
$parentForm = $this->closest("form");
if(!is_null($parentForm)) {
$this->removeAttributeFromNamedElementAndChildren(
$parentForm,
$this->getAttribute("name"),
"checked"
);
}
}
$this->setAttribute("checked", "checked");
} else {
$this->removeAttribute("checked");
}
return $this->checked;
}
public function prop_get_selected(){
return $this->hasAttribute("selected");
}
public function prop_set_selected($selected){
if($selected) {
$selectElement = $this->closest("select");
if(!$selectElement->hasAttribute("multiple")) {
$this->removeAttributeFromNamedElementAndChildren(
$selectElement->closest("form"),
$selectElement->getAttribute("name"),
"selected"
);
}
$this->setAttribute("selected", true);
} else {
$this->removeAttribute("selected");
}
return $this->selected;
}
public function prop_get_form(){
if(in_array($this->tagName, self::FORM_CONTROL_ELEMENTS)) {
if($this->tagName === "input"
&& $this->getAttribute("type") === "image") {
return null;
}
if($this->hasAttribute("form")) {
return $this->getRootDocument()->getElementById(
$this->getAttribute("form")
)
;
} else {
return $this->closest('form');
}
}
return null;
}
public function prop_get_valueAsDate(){
if($this->tagName === "input") {
return new DateTime($this->value);
}
}
public function prop_get_valueAsNumber(){
if($this->tagName === "input") {
return (float) $this->value;
}
}
protected function createDataset(){
return new StringMap(
$this,
$this->attributes
);
}
protected function getRootDocument(){
return $this->ownerDocument;
}
private function value_set_select($newValue){
$options = $this->getElementsByTagName('option');
$selectedIndexes = [];
$newSelectedIndex = null;
for($i = $options->length-1; $i >= 0; --$i) {
$option = $options->item($i);
if($this->isSelectOptionSelected($option)) {
$selectedIndexes [] = $i;
}
if($option->hasAttribute("value")) {
if($option->getAttribute("value") == $newValue) {
$newSelectedIndex = $i;
}
} else {
if(trim($option->innerText) === $newValue) {
$newSelectedIndex = $i;
}
}
}
if($newSelectedIndex !== null) {
foreach($selectedIndexes as $i) {
$options->item($i)->removeAttribute('selected');
}
$options->item($newSelectedIndex)->setAttribute('selected', 'selected');
}
}
private function value_get_select(){
$options = $this->getElementsByTagName('option');
if($options->length == 0) {
$value = '';
} else {
$value = $options->item(0)->getAttribute('value');
}
foreach($options as $option) {
if($this->isSelectOptionSelected($option)) {
$value = $option->getAttribute('value');
$value = $value ? $value : trim($option->innerText);
break;
}
}
return $value ? $value : "";
}
private function value_set_input($newValue){
return $this->setAttribute("value", $newValue);
}
private function value_get_input(){
return $this->getAttribute("value");
}
public function isSelectOptionSelected(Element $option){
return $option->hasAttribute('selected') && $option->getAttribute('selected');
}
public function __debugInfo(){
return [
'nodeName' => $this->nodeName,
'nodeValue' => $this->nodeValue,
'innerHTML' => $this->innerHTML,
"class" => $this->className,
"id" => $this->id,
"name" => $this->getAttribute("name"),
"type" => $this->getAttribute("type"),
"src" => $this->getAttribute("src"),
"href" => $this->getAttribute("href"),
];
}
public function wpda_replaceWith(\DOMNode $replacement){
$this->parentNode->insertBefore($replacement, $this);
$this->parentNode->removeChild($this);
}
}