requestStack = $request_stack; $this->httpClient = $http_client; $this->renderer = $renderer; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), $container->get('state.advagg.files'), $container->get('state.advagg.aggregates'), $container->get('request_stack'), $container->get('http_client'), $container->get('renderer') ); } /** * {@inheritdoc} */ public function getFormId() { return 'advagg_validator_cssw3'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form = parent::generateForm('css', FALSE); $form['notice'] = [ '#markup' => '
' . t('Notice: The form below will submit files to the http://jigsaw.w3.org/css-validator/ service if used.') . '
', '#weight' => -1, ]; $form = parent::buildForm($form, $form_state); unset($form['actions']); return $form; } /** * {@inheritdoc} */ public function submitCheckAll(array &$form, FormStateInterface $form_state) { $dir = $form_state->getTriggeringElement()['#name']; $files = []; foreach ($form_state->getValues() as $key => $value) { if (strpos($key, 'hidden') === FALSE || strpos($value, $dir) === FALSE || ($dir === '.' && substr_count($value, '/') > 0)) { continue; } $files[] = $value; } // Check list. $info = $this->testFiles($files); $info = $this->hideGoodFiles($info); $output = [ '#theme' => 'item_list', '#items' => $info, ]; drupal_set_message($this->renderer->render($output)); } /** * Display validation info via ajax callback. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ public function ajaxCheck(array &$form, FormStateInterface $form_state) { $dir = $form_state->getTriggeringElement()['#name']; return $this->getElement($form, explode('/', $dir))['wrapper']; } /** * {@inheritdoc} */ public function submitCheckDirectory(array &$form, FormStateInterface $form_state) { $dir = $form_state->getTriggeringElement()['#name']; $files = []; $slash_count = substr_count('/' . $dir, '/'); foreach ($form_state->getValues() as $key => $value) { if (strpos($key, 'hidden') === FALSE || strpos($value, $dir) === FALSE || substr_count($value, '/') > $slash_count || ($dir === '.' && substr_count($value, '/') > 0)) { continue; } $files[] = $value; } // Check list. $info = $this->testFiles($files); $info = $this->hideGoodFiles($info); $output = [ '#theme' => 'item_list', '#items' => $info, ]; drupal_set_message($this->renderer->render($output)); } /** * {@inheritdoc} */ protected function testFiles(array $files, array $options = []) { $output = []; $file_info = $this->advaggFiles->getMultiple($files); foreach ($files as $filename) { // Skip missing files. if (!file_exists($filename)) { continue; } $file_contents = file_get_contents($filename); $lines = file($filename); $content_hash = Crypt::hashBase64($file_contents); // If saved file information not current update filestore. if ($file_info[$filename]['content_hash'] != $content_hash) { $this->advagg_files->scanFile($filename, $file_info[$filename], $file_contents); } // If saved validation results available use them rather than re-run. if (isset($file_info[$filename]['validation']['w3'])) { $output[$filename]['jigsaw.w3.org'] = $file_info[$filename]['validation']['w3']; continue; } // Run jigsaw.w3.org validator. $output[$filename]['jigsaw.w3.org'] = $this->testW3C($filename, $options); // Get extra context for errors. if (!empty($output[$filename]['jigsaw.w3.org']['errors'])) { foreach ($output[$filename]['jigsaw.w3.org']['errors'] as &$value) { if (isset($value['line'])) { $value['linedata'] = $lines[($value['line'] - 1)]; if (strlen($value['linedata']) > 512) { unset($value['linedata']); } } } unset($value); } if (!empty($output[$filename]['jigsaw.w3.org']['warnings'])) { foreach ($output[$filename]['jigsaw.w3.org']['warnings'] as &$value) { if (isset($value['line'])) { $value['linedata'] = $lines[$value['line'] - 1]; if (strlen($value['linedata']) > 512) { unset($value['linedata']); } } } unset($value); } // Save data. $file_info[$filename]['validation']['w3'] = $output[$filename]['jigsaw.w3.org']; $this->advaggFiles->set($filename, $file_info[$filename]); } return $output; } /** * Given a CSS file, test to make sure it is valid CSS. * * @param string $filename * The name of the file. * @param array $validator_options * List of options to pass along to the CSS Validator. * * @return array * Info from the w3c server. */ private function testW3C($filename, array &$validator_options = []) { // Get CSS files contents. $validator_options['text'] = file_get_contents($filename); if (strlen($validator_options['text']) > 50000) { unset($validator_options['text']); $validator_options['uri'] = $this->requestStack->getCurrentRequest()->getBaseUrl() . $filename; } // Add in defaults. $validator_options += [ 'output' => 'soap12', 'warning' => '1', 'profile' => 'css3', 'usermedium' => 'all', 'lang' => 'en', ]; // Build request URL. // API Documentation http://jigsaw.w3.org/css-validator/api.html $request_url = 'http://jigsaw.w3.org/css-validator/validator'; $query = http_build_query($validator_options, '', '&'); $url = $request_url . '?' . $query; try { $data = $this->httpClient ->get($url) ->getBody(); } catch (RequestException $e) { watchdog_exception('AdvAgg Validator', $e); } catch (\Exception $e) { watchdog_exception('AdvAgg Validator', $e); } if (!empty($data)) { // Parse XML and return info. $return = $this->parseSoapResponse($data); $return['filename'] = $filename; if (isset($validator_options['text'])) { unset($validator_options['text']); } elseif (isset($validator_options['uri'])) { unset($validator_options['uri']); } $return['options'] = $validator_options; return $return; } return ['error' => t('W3C Server did not return a 200 or request data was empty.')]; } /** * {@inheritdoc} */ private function parseSoapResponse($xml) { $doc = new DOMDocument(); $response = []; // Try to load soap 1.2 XML response, and suppress warning reports if any. if (!@$doc->loadXML($xml)) { // Could not load the XML document. return $response; } // Get the standard CDATA elements. $cdata = ['uri', 'checkedby', 'csslevel', 'date']; foreach ($cdata as $var) { $element = $doc->getElementsByTagName($var); if ($element->length) { $response[$var] = $element->item(0)->nodeValue; } } // Handle the element validity and get errors if not valid. $element = $doc->getElementsByTagName('validity'); if ($element->length && $element->item(0)->nodeValue === 'true') { $response['validity'] = TRUE; } else { $response['validity'] = FALSE; $errors = $doc->getElementsByTagName('error'); foreach ($errors as $error) { $response['errors'][] = $this->domExtractor($error); } } // Get warnings. $warnings = $doc->getElementsByTagName('warning'); foreach ($warnings as $warning) { $response['warnings'][] = $this->domExtractor($warning); } // Return response array. return $response; } }