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: 27: 28: 29:
30: protected $_doubleTags = array(
31: "form",
32: "head",
33: "body",
34: "html",
35: "td",
36: "tr",
37: "table",
38: "a",
39: "tbody",
40: "title",
41: "container",
42: "span",
43: "div"
44: );
45:
46: 47: 48: 49:
50: public $missingNodes = array();
51:
52: 53: 54: 55: 56:
57: public $iNodeName;
58:
59: 60: 61: 62:
63: protected $_html;
64:
65: 66: 67: 68:
69: protected $_nestingLevel = array();
70:
71: 72: 73: 74:
75: protected $_nestingNodes = array();
76:
77: 78: 79: 80:
81: protected $_existingTags = array();
82:
83: 84: 85: 86:
87: public function validate($html) {
88: $nestingLevel = 0;
89:
90:
91: $this->_html = $this->_cleanHTML($html);
92:
93: $htmlParser = new HtmlParser($this->_html);
94:
95: while ($htmlParser->parse()) {
96: $this->_existingTags[] = $htmlParser->iNodeName;
97:
98: if (in_array($htmlParser->iNodeName, $this->_doubleTags)) {
99: if (!array_key_exists($htmlParser->iNodeName, $this->_nestingLevel)) {
100: $this->_nestingLevel[$htmlParser->iNodeName] = 0;
101: }
102:
103: if (!array_key_exists($htmlParser->iNodeName, $this->_nestingNodes)) {
104: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])] = array();
105: }
106:
107:
108: if ($htmlParser->iNodeType == HtmlParser::NODE_TYPE_ELEMENT) {
109:
110:
111: $nestingLevel++;
112:
113: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["name"] = $htmlParser->iNodeAttributes["name"];
114: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["id"] = $htmlParser->iNodeAttributes["id"];
115: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["level"] = $nestingLevel;
116: $this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["char"] = $htmlParser->iHtmlTextIndex;
117: $this->_nestingLevel[$htmlParser->iNodeName]++;
118: }
119:
120: if ($htmlParser->iNodeType == HtmlParser::NODE_TYPE_ENDELEMENT) {
121:
122: if ($this->_nestingLevel[$htmlParser->iNodeName] > 0) {
123: unset($this->_nestingNodes[$htmlParser->iNodeName][$this->_nestingLevel[$htmlParser->iNodeName]]);
124: $this->_nestingLevel[$htmlParser->iNodeName]--;
125:
126: if ($this->_nestingNodes[$htmlParser->iNodeName][intval($this->_nestingLevel[$htmlParser->iNodeName])]["level"] != $nestingLevel) {
127:
128: }
129:
130: $nestingLevel--;
131: }
132: }
133: }
134: }
135:
136:
137: $this->missingNodes = array();
138:
139:
140: foreach ($this->_nestingLevel as $key => $value) {
141:
142: if ($value > 0) {
143:
144: for ($i = 0; $i < $value; $i++) {
145: $node = $this->_nestingNodes[$key][$i];
146:
147: list($line, $char) = $this->_getLineAndCharPos($node["char"]);
148: $this->missingNodes[] = array(
149: "tag" => $key,
150: "id" => $node["id"],
151: "name" => $node["name"],
152: "line" => $line,
153: "char" => $char
154: );
155:
156: $this->missingTags[$line][$char] = true;
157: }
158: }
159: }
160: }
161:
162: 163: 164: 165: 166:
167: public function tagExists($tag) {
168: if (in_array($tag, $this->_existingTags)) {
169: return true;
170: } else {
171: return false;
172: }
173: }
174:
175: 176: 177: 178: 179:
180: protected function _cleanHTML($html) {
181:
182: $resultingHTML = preg_replace('/<\?(php)?((.)|(\s))*?\?>/i', '', $html);
183:
184:
185:
186: $resultingHTML = str_replace("\r\n", "\n", $resultingHTML);
187: $resultingHTML = str_replace("\r", "\n", $resultingHTML);
188:
189: return $resultingHTML;
190: }
191:
192: 193: 194: 195: 196:
197: protected function _returnErrorMap() {
198: $html = "<pre>";
199:
200: $chunks = explode("\n", $this->_html);
201:
202: foreach ($chunks as $key => $value) {
203: $html .= ($key + 1) . " ";
204:
205: for ($i = 0; $i < strlen($value); $i++) {
206: $char = substr($value, $i, 1);
207:
208: if (is_array($this->missingTags[$key + 1])) {
209:
210: if (array_key_exists($i + 2, $this->missingTags[$key + 1])) {
211: $html .= "<u><b>" . conHtmlSpecialChars($char) . "</b></u>";
212: } else {
213: $html .= conHtmlSpecialChars($char);
214: }
215: } else {
216: $html .= conHtmlSpecialChars($char);
217: }
218: }
219:
220: $html .= "<br>";
221: }
222:
223: return $html;
224: }
225:
226: 227: 228: 229: 230:
231: protected function _getLineAndCharPos($charpos) {
232: $mangled = substr($this->_html, 0, $charpos);
233:
234: $line = substr_count($mangled, "\n") + 1;
235: $char = $charpos - strrpos($mangled, "\n");
236:
237: return array(
238: $line,
239: $char
240: );
241: }
242: }
243: