@@ -9,12 +9,21 @@ class HTMLValidator
99 *
1010 * @var string
1111 */
12- protected $ validatorUri = 'http://validator.w3.org/check ' ;
12+ private $ validatorUri = 'http://validator.w3.org/nu/ ' ;
1313
1414 /**
1515 * @var Options
1616 */
17- protected $ options ;
17+ private $ options ;
18+
19+ /**
20+ * Default context for http request.
21+ *
22+ * @see https://www.php.net/manual/en/context.php
23+ *
24+ * @var array
25+ */
26+ private $ context = [];
1827
1928 public function __construct (Options $ options = null )
2029 {
@@ -33,6 +42,18 @@ public function setOptions(Options $options): self
3342 return $ this ;
3443 }
3544
45+ public function getContext (): array
46+ {
47+ return $ this ->context ;
48+ }
49+
50+ public function setContext (array $ context ): self
51+ {
52+ $ this ->context = $ context ;
53+
54+ return $ this ;
55+ }
56+
3657 public function getValidatorUri (): string
3758 {
3859 return $ this ->validatorUri ;
@@ -46,15 +67,21 @@ public function setValidatorUri(string $validatorUri): self
4667 }
4768
4869 /**
49- * @param resource $context
50- *
5170 * @throws Exception
5271 */
53- protected function sendRequest (string $ uri , $ context = null ): string
72+ protected function sendRequest (string $ uri , array $ context ): string
5473 {
55- $ data = \file_get_contents ($ uri , null , $ context );
74+ $ context = \array_merge ($ this ->getContext (), $ context );
75+
76+ if (isset ($ context ['http ' ]['header ' ])) {
77+ $ context ['http ' ]['header ' ] .= "\r\nUser-Agent: gemorroj/htmlvalidator " ;
78+ } else {
79+ $ context ['http ' ]['header ' ] = 'User-Agent: gemorroj/htmlvalidator ' ;
80+ }
81+
82+ $ data = @\file_get_contents ($ uri , false , \stream_context_create ($ context ));
5683 if (false === $ data ) {
57- throw new Exception (' Error send request ' );
84+ throw new Exception (\error_get_last ()[ ' message ' ] );
5885 }
5986
6087 return $ data ;
@@ -68,27 +95,25 @@ protected function sendRequest(string $uri, $context = null): string
6895 *
6996 * @param string $uri The address to the page to validate ex: http://example.com/
7097 *
71- * @throws Exception
72- *
73- * @return Response object HTMLValidator\Response
98+ * @throws Exception|\JsonException
7499 */
75100 public function validateUri (string $ uri ): Response
76101 {
77102 $ query = \http_build_query (\array_merge (
78103 $ this ->getOptions ()->buildOptions (),
79- ['uri ' => $ uri ]
104+ ['doc ' => $ uri, ' out ' => ' json ' ]
80105 ));
81106
82- $ context = \stream_context_create ( [
107+ $ context = [
83108 'http ' => [
84109 'method ' => 'GET ' ,
85- 'header ' => 'User-Agent: HTMLValidator ' ,
110+ 'header ' => 'Content-Type: text/html; charset=utf-8 ' ,
86111 ],
87- ]) ;
112+ ];
88113
89114 $ data = $ this ->sendRequest ($ this ->validatorUri .'? ' .$ query , $ context );
90115
91- return $ this ->parseSOAP12Response ($ data );
116+ return $ this ->parseJsonResponse ($ data );
92117 }
93118
94119 /**
@@ -98,7 +123,7 @@ public function validateUri(string $uri): Response
98123 *
99124 * @param string $file file to be validated
100125 *
101- * @throws Exception
126+ * @throws Exception|\JsonException
102127 *
103128 * @return Response object HTMLValidator\Response
104129 */
@@ -111,9 +136,9 @@ public function validateFile(string $file): Response
111136 throw new Exception ('File not readable ' );
112137 }
113138
114- $ data = \file_get_contents ($ file );
139+ $ data = @ \file_get_contents ($ file );
115140 if (false === $ data ) {
116- throw new Exception (' Failed get file ' );
141+ throw new Exception (\error_get_last ()[ ' message ' ] );
117142 }
118143
119144 return $ this ->validateFragment ($ data );
@@ -124,76 +149,62 @@ public function validateFile(string $file): Response
124149 *
125150 * @param string $html full html document fragment
126151 *
127- * @throws Exception
152+ * @throws Exception|\JsonException
128153 *
129154 * @return Response object HTMLValidator\Response
130155 */
131156 public function validateFragment (string $ html ): Response
132157 {
133158 $ query = \http_build_query (\array_merge (
134159 $ this ->getOptions ()->buildOptions (),
135- ['fragment ' => $ html ]
160+ ['out ' => ' json ' ]
136161 ));
137162
138- $ context = \stream_context_create ( [
163+ $ context = [
139164 'http ' => [
140165 'method ' => 'POST ' ,
141- 'header ' => " Content-Type: application/x-www-form-urlencoded \r\n User-Agent: HTMLValidator " ,
142- 'content ' => $ query ,
166+ 'header ' => ' Content-Type: text/html; charset=utf-8 ' ,
167+ 'content ' => $ html ,
143168 ],
144- ]) ;
169+ ];
145170
146- $ data = $ this ->sendRequest ($ this ->validatorUri , $ context );
171+ $ data = $ this ->sendRequest ($ this ->validatorUri . ' ? ' . $ query , $ context );
147172
148- return $ this ->parseSOAP12Response ($ data );
173+ return $ this ->parseJsonResponse ($ data );
149174 }
150175
151176 /**
152- * Parse an XML response from the validator.
177+ * Parse an JSON response from the validator.
153178 *
154- * This function parses a SOAP 1.2 response xml string from the validator.
179+ * This function parses a JSON response json string from the validator.
155180 *
156- * @param string $xml the raw soap12 XML response from the validator
157- *
158- * @throws Exception
181+ * @param string $json the raw JSON response from the validator
159182 *
160- * @return Response object HTMLValidator\Response
183+ * @throws Exception|\JsonException
161184 */
162- protected function parseSOAP12Response (string $ xml ): Response
185+ protected function parseJsonResponse (string $ json ): Response
163186 {
164- $ doc = new \DOMDocument ('1.0 ' , 'UTF-8 ' );
165-
166- if (false === $ doc ->loadXML ($ xml )) {
167- throw new Exception ('Failed load xml ' );
168- }
187+ $ data = \json_decode ($ json , true , 512 , \JSON_THROW_ON_ERROR );
169188
170189 $ response = new Response ();
171190
172- // Get the standard CDATA elements
173- foreach (['uri ' , 'checkedby ' , 'doctype ' , 'charset ' ] as $ var ) {
174- $ element = $ doc ->getElementsByTagName ($ var );
175- if ($ element ->length ) {
176- $ response ->{'set ' .\ucfirst ($ var )}($ element ->item (0 )->nodeValue );
177- }
178- }
191+ $ response ->setEncoding ($ data ['source ' ]['encoding ' ] ?? null );
192+ $ response ->setType ($ data ['source ' ]['type ' ] ?? null );
193+ $ response ->setUri ($ data ['url ' ] ?? null );
179194
180- // Handle the bool element validity
181- $ element = $ doc ->getElementsByTagName ('validity ' );
182- if ($ element ->length && 'true ' === $ element ->item (0 )->nodeValue ) {
183- $ response ->setValidity (true );
184- } else {
185- $ response ->setValidity (false );
195+ if (isset ($ data ['messages ' ][0 ]['type ' ]) && 'non-document-error ' === $ data ['messages ' ][0 ]['type ' ]) {
196+ throw new Exception ($ data ['messages ' ][0 ]['message ' ]);
186197 }
187198
188- if (!$ response ->isValidity ()) {
189- $ errors = $ doc ->getElementsByTagName ('error ' );
190- foreach ($ errors as $ error ) {
191- $ response ->addError (new Error ($ error ));
199+ $ response ->setValid (true );
200+ foreach ($ data ['messages ' ] as $ message ) {
201+ if ('error ' === $ message ['type ' ]) {
202+ $ response ->setValid (false );
203+ $ response ->addError (new Error ($ message ));
204+ }
205+ if ('info ' === $ message ['type ' ]) { // warning
206+ $ response ->addWarning (new Warning ($ message ));
192207 }
193- }
194- $ warnings = $ doc ->getElementsByTagName ('warning ' );
195- foreach ($ warnings as $ warning ) {
196- $ response ->addWarning (new Warning ($ warning ));
197208 }
198209
199210 return $ response ;
0 commit comments