1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
17:
18: 19: 20: 21: 22: 23:
24: class cHTMLValidator {
25:
26: protected $_doubleTags = array(
27: "form",
28: "head",
29: "body",
30: "html",
31: "td",
32: "tr",
33: "table",
34: "a",
35: "tbody",
36: "title",
37: "container",
38: "span",
39: "div"
40: );
41:
42: protected $_html;
43:
44: protected $_nestingLevel = array();
45:
46: public $missingNodes = array();
47:
48: public $iNodeName;
49:
50: protected $_nestingNodes = array();
51:
52: protected $_existingTags = array();
53:
54: protected function _cleanHTML($html) {
55:
56: $resultingHTML = preg_replace('/<\?(php)?((.)|(\s))*?\?>/i', '', $html);
57:
58:
59:
60: $resultingHTML = str_replace("\r\n", "\n", $resultingHTML);
61: $resultingHTML = str_replace("\r", "\n", $resultingHTML);
62:
63: return $resultingHTML;
64: }
65:
66: public function validate($html) {
67: $nestingLevel = 0;
68:
69:
70: $this->_html = $this->_cleanHTML($html);
71:
72: $htmlParser = new HtmlParser($this->_html);
73:
74: while ($htmlParser->parse()) {
75: $this->_existingTags[] = $htmlParser->iNodeName;
76:
77: if (in_array($htmlParser->iNodeName, $this->_doubleTags)) {
78: if (!array_key_exists($htmlParser->iNodeName, $this->_nestingLevel)) {
79: $this->_nestingLevel[$htmlParser->iNodeName] = 0;
80: }
81:
82: if (!array_key_exists($htmlParser->iNodeName, $this->_nestingNodes)) {
83: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])] = array();
84: }
85:
86:
87: if ($htmlParser->iNodeType == HtmlParser::NODE_TYPE_ELEMENT) {
88:
89:
90: $nestingLevel++;
91:
92: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["name"] = $htmlParser->iNodeAttributes["name"];
93: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["id"] = $htmlParser->iNodeAttributes["id"];
94: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["level"] = $nestingLevel;
95: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["char"] = $htmlParser->iHtmlTextIndex;
96: $this->_nestingLevel[$htmlParser->iNodeName]++;
97: }
98:
99: if ($htmlParser->iNodeType == HtmlParser::NODE_TYPE_ENDELEMENT) {
100:
101: if ($this->_nestingLevel[$htmlParser->iNodeName] > 0) {
102: unset($this->_nestingNodes[$htmlParser->iNodeName][$this->_nestingLevel[$htmlParser->iNodeName]]);
103: $this->_nestingLevel[$htmlParser->iNodeName]--;
104:
105: if ($this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["level"] != $nestingLevel) {
106:
107: }
108:
109: $nestingLevel--;
110: }
111: }
112: }
113: }
114:
115:
116: $this->missingNodes = array();
117:
118:
119: foreach ($this->_nestingLevel as $key => $value) {
120:
121: if ($value > 0) {
122:
123: for ($i = 0; $i < $value; $i++) {
124: $node = $this->_nestingNodes[$key][$i];
125:
126: list($line, $char) = $this->_getLineAndCharPos($node["char"]);
127: $this->missingNodes[] = array(
128: "tag" => $key,
129: "id" => $node["id"],
130: "name" => $node["name"],
131: "line" => $line,
132: "char" => $char
133: );
134:
135: $this->missingTags[$line][$char] = true;
136: }
137: }
138: }
139: }
140:
141: public function tagExists($tag) {
142: if (in_array($tag, $this->_existingTags)) {
143: return true;
144: } else {
145: return false;
146: }
147: }
148:
149: protected function _returnErrorMap() {
150: $html = "<pre>";
151:
152: $chunks = explode("\n", $this->_html);
153:
154: foreach ($chunks as $key => $value) {
155: $html .= ($key + 1) . " ";
156:
157: for ($i = 0; $i < strlen($value); $i++) {
158: $char = substr($value, $i, 1);
159:
160: if (is_array($this->missingTags[$key + 1])) {
161:
162: if (array_key_exists($i + 2, $this->missingTags[$key + 1])) {
163: $html .= "<u><b>" . conHtmlSpecialChars($char) . "</b></u>";
164: } else {
165: $html .= conHtmlSpecialChars($char);
166: }
167: } else {
168: $html .= conHtmlSpecialChars($char);
169: }
170: }
171:
172: $html .= "<br>";
173: }
174:
175: return $html;
176: }
177:
178: protected function _getLineAndCharPos($charpos) {
179: $mangled = substr($this->_html, 0, $charpos);
180:
181: $line = substr_count($mangled, "\n") + 1;
182: $char = $charpos - strrpos($mangled, "\n");
183:
184: return array(
185: $line,
186: $char
187: );
188: }
189:
190: }
191: