1 file.inc file_validate_svg(File $file)

Validate uploaded SVG files.

Parameters

File $file: A file entity.

Return value

array: If the file is an SVG and is either not valid or contains dangerous content, the array will contain an error message.

See also

hook_file_validate()

Related topics

File

core/includes/file.inc, line 2036
API for handling file uploads and server file management.

Code

function file_validate_svg(File $file) {
  $errors = array();

  if ($file->filemime == 'image/svg+xml') {
    $file_contents = file_get_contents($file->uri);
    $file_contents = preg_replace('/<!DOCTYPE[^>]*>/i', '', $file_contents);
    $file_contents = html_entity_decode($file_contents);
    $file_contents = strtolower($file_contents);
    libxml_use_internal_errors(TRUE);
    $xml = simplexml_load_string($file_contents);
    $errors = libxml_get_errors();

    if (!$xml || !empty($errors)) {
      return array(t('Invalid SVG file.'));
    }
    else {
      $errors = array();
      $namespaces = $xml->getNamespaces();
      if (!in_array('http://www.w3.org/2000/svg', $namespaces)) {
        $errors[] = t('Invalid SVG namespace.');
      }

      $search_patterns = array(
        // @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element
        '//svg:foreignobject',
        '//svg:script',
        '//html:iframe',
        // @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute
        '//@*[starts-with(name(), "on")]',
        '//svg:a[starts-with(normalize-space(@href), "javascript:")]',
        '//svg:a[starts-with(normalize-space(@xlink:href), "javascript:")]',
        '//svg:a[starts-with(normalize-space(@href), "data:")]',
        '//svg:a[starts-with(normalize-space(@xlink:href), "data:")]',
      );

      $xml->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
      $xml->registerXPathNamespace('html', 'http://www.w3.org/1999/xhtml');
      foreach ($search_patterns as $search_pattern) {
        $found = $xml->xpath($search_pattern);
        if (!empty($found)) {
          $errors[] = t('Dangerous content found.');
          break;
        }
      }
    }
    libxml_clear_errors();
    libxml_use_internal_errors(FALSE);
  }

  return $errors;
}