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