Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
authorJeff Veit <jeff.veit@gmail.com>
Mon, 25 Oct 2021 18:16:40 +0000 (19:16 +0100)
committerJeff Veit <jeff.veit@gmail.com>
Mon, 25 Oct 2021 18:44:17 +0000 (19:44 +0100)
76 files changed:
composer.json
composer.lock
vendor/composer/ClassLoader.php
vendor/composer/autoload_real.php
vendor/composer/installed.json
web/libraries/htmLawed/htmLawed.php
web/libraries/htmLawed/htmLawedTest.php [new file with mode: 0755]
web/libraries/htmLawed/htmLawed_README.htm [new file with mode: 0644]
web/libraries/htmLawed/htmLawed_README.txt
web/libraries/htmLawed/htmLawed_TESTCASE.txt [new file with mode: 0755]
web/modules/contrib/htmlawed/htmLawed/htmLawed.php
web/modules/contrib/htmlawed/htmLawed/htmLawed_README.htm
web/modules/contrib/htmlawed/htmlawed.info.yml
web/modules/contrib/htmlawed/readme.txt
web/modules/contrib/htmlawed/src/Plugin/Filter/Filterhtmlawed.php
web/modules/contrib/security_review/API.txt [deleted file]
web/modules/contrib/security_review/IGNOREME.txt [deleted file]
web/modules/contrib/security_review/PATCHES.txt [deleted file]
web/modules/contrib/security_review/README.txt [deleted file]
web/modules/contrib/security_review/config/install/security_review.check.security_review-base_url_set.yml [deleted file]
web/modules/contrib/security_review/config/install/security_review.settings.yml [deleted file]
web/modules/contrib/security_review/config/schema/security_review.schema.yml [deleted file]
web/modules/contrib/security_review/css/security_review.run_and_review.css [deleted file]
web/modules/contrib/security_review/js/security_review.run_and_review.js [deleted file]
web/modules/contrib/security_review/security_review.api.php [deleted file]
web/modules/contrib/security_review/security_review.drush.inc [deleted file]
web/modules/contrib/security_review/security_review.info.yml [deleted file]
web/modules/contrib/security_review/security_review.install [deleted file]
web/modules/contrib/security_review/security_review.libraries.yml [deleted file]
web/modules/contrib/security_review/security_review.links.menu.yml [deleted file]
web/modules/contrib/security_review/security_review.links.task.yml [deleted file]
web/modules/contrib/security_review/security_review.module [deleted file]
web/modules/contrib/security_review/security_review.permissions.yml [deleted file]
web/modules/contrib/security_review/security_review.routing.yml [deleted file]
web/modules/contrib/security_review/security_review.services.yml [deleted file]
web/modules/contrib/security_review/src/Check.php [deleted file]
web/modules/contrib/security_review/src/CheckResult.php [deleted file]
web/modules/contrib/security_review/src/CheckSettings.php [deleted file]
web/modules/contrib/security_review/src/CheckSettings/TrustedHostSettings.php [deleted file]
web/modules/contrib/security_review/src/CheckSettingsInterface.php [deleted file]
web/modules/contrib/security_review/src/Checklist.php [deleted file]
web/modules/contrib/security_review/src/Checks/AdminPermissions.php [deleted file]
web/modules/contrib/security_review/src/Checks/ErrorReporting.php [deleted file]
web/modules/contrib/security_review/src/Checks/ExecutablePhp.php [deleted file]
web/modules/contrib/security_review/src/Checks/FailedLogins.php [deleted file]
web/modules/contrib/security_review/src/Checks/Field.php [deleted file]
web/modules/contrib/security_review/src/Checks/Field.php.rej [deleted file]
web/modules/contrib/security_review/src/Checks/FilePermissions.php [deleted file]
web/modules/contrib/security_review/src/Checks/InputFormats.php [deleted file]
web/modules/contrib/security_review/src/Checks/PrivateFiles.php [deleted file]
web/modules/contrib/security_review/src/Checks/QueryErrors.php [deleted file]
web/modules/contrib/security_review/src/Checks/TemporaryFiles.php [deleted file]
web/modules/contrib/security_review/src/Checks/TrustedHosts.php [deleted file]
web/modules/contrib/security_review/src/Checks/UploadExtensions.php [deleted file]
web/modules/contrib/security_review/src/Checks/ViewsAccess.php [deleted file]
web/modules/contrib/security_review/src/Controller/ChecklistController.php [deleted file]
web/modules/contrib/security_review/src/Controller/HelpController.php [deleted file]
web/modules/contrib/security_review/src/Controller/ToggleController.php [deleted file]
web/modules/contrib/security_review/src/Form/RunForm.php [deleted file]
web/modules/contrib/security_review/src/Form/SettingsForm.php [deleted file]
web/modules/contrib/security_review/src/Security.php [deleted file]
web/modules/contrib/security_review/src/SecurityReview.php [deleted file]
web/modules/contrib/security_review/src/Tests/CheckWebTest.php [deleted file]
web/modules/contrib/security_review/src/Tests/ChecklistWebTest.php [deleted file]
web/modules/contrib/security_review/templates/check_evaluation.html.twig [deleted file]
web/modules/contrib/security_review/templates/check_help.html.twig [deleted file]
web/modules/contrib/security_review/templates/general_help.html.twig [deleted file]
web/modules/contrib/security_review/templates/run_and_review.html.twig [deleted file]
web/modules/contrib/security_review/tests/modules/security_review_test/security_review_test.info.yml [deleted file]
web/modules/contrib/security_review/tests/modules/security_review_test/security_review_test.module [deleted file]
web/modules/contrib/security_review/tests/modules/security_review_test/src/Test.php [deleted file]
web/modules/contrib/security_review/tests/modules/security_review_test/src/TestNoStore.php [deleted file]
web/modules/contrib/security_review/tests/src/Kernel/CheckTest.php [deleted file]
web/modules/contrib/security_review/tests/src/Kernel/ChecklistTest.php [deleted file]
web/modules/contrib/security_review/tests/src/Kernel/SecurityReviewTest.php [deleted file]
web/sites/default/default.settings.php

index c514b311020fb3ac0801bdb4041a3de9da5ec65a..bea1fd9b4533734521c31b58bcd975ed718c0500 100644 (file)
@@ -89,7 +89,6 @@
         "drupal/inline_entity_form": "^1.0@beta",
         "drupal/entity_embed": "^1.0@beta",
         "drupal/dropzonejs": "^2.0@alpha",
         "drupal/inline_entity_form": "^1.0@beta",
         "drupal/entity_embed": "^1.0@beta",
         "drupal/dropzonejs": "^2.0@alpha",
-        "drupal/security_review": "1.x-dev",
         "drupal/entity_reference_revisions": "^1.6",
         "drupal/entity": "^1.0-rc1"
     },
         "drupal/entity_reference_revisions": "^1.6",
         "drupal/entity": "^1.0-rc1"
     },
@@ -98,7 +97,7 @@
         "behat/mink-goutte-driver": "~1.2",
         "jcalderonzumba/gastonjs": "~1.0.2",
         "jcalderonzumba/mink-phantomjs-driver": "~0.3.1",
         "behat/mink-goutte-driver": "~1.2",
         "jcalderonzumba/gastonjs": "~1.0.2",
         "jcalderonzumba/mink-phantomjs-driver": "~0.3.1",
-        "mikey179/vfsStream": "~1.2",
+        "mikey179/vfsstream": "~1.2",
         "symfony/css-selector": "~2.8",
         "drupal/twig_xdebug": "^1.0",
         "drupal/livereload": "1.x-dev",
         "symfony/css-selector": "~2.8",
         "drupal/twig_xdebug": "^1.0",
         "drupal/livereload": "1.x-dev",
index 38cdf935ff9010faee6dd064b88901330ea40356..7c7370821082d195877938a5d219cf61f9225fa8 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "2c9cad0804408626752bffa44fe2bec6",
+    "content-hash": "8cfc3879a25f15d6aba3eaccfc3cb818",
     "packages": [
         {
             "name": "alchemy/zippy",
     "packages": [
         {
             "name": "alchemy/zippy",
             ],
             "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
             "homepage": "https://github.com/container-interop/container-interop",
             ],
             "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
             "homepage": "https://github.com/container-interop/container-interop",
+            "abandoned": "psr/container",
             "time": "2017-02-14T19:40:03+00:00"
         },
         {
             "time": "2017-02-14T19:40:03+00:00"
         },
         {
                 "GPL-2.0-or-later"
             ],
             "description": "Composer Plugin for updating the Drupal scaffold files when using drupal/core",
                 "GPL-2.0-or-later"
             ],
             "description": "Composer Plugin for updating the Drupal scaffold files when using drupal/core",
+            "abandoned": "drupal/core-composer-scaffold",
             "time": "2018-07-27T10:07:07+00:00"
         },
         {
             "time": "2018-07-27T10:07:07+00:00"
         },
         {
             "version": "1.24.0",
             "source": {
                 "type": "git",
             "version": "1.24.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/admin_toolbar",
+                "url": "https://git.drupalcode.org/project/admin_toolbar.git",
                 "reference": "8.x-1.24"
             },
             "dist": {
                 "reference": "8.x-1.24"
             },
             "dist": {
             "version": "2.4.0",
             "source": {
                 "type": "git",
             "version": "2.4.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/advagg",
+                "url": "https://git.drupalcode.org/project/advagg.git",
                 "reference": "8.x-2.4"
             },
             "dist": {
                 "reference": "8.x-2.4"
             },
             "dist": {
             "version": "1.0.0-alpha2",
             "source": {
                 "type": "git",
             "version": "1.0.0-alpha2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/advanced_help",
+                "url": "https://git.drupalcode.org/project/advanced_help.git",
                 "reference": "8.x-1.0-alpha2"
             },
             "dist": {
                 "reference": "8.x-1.0-alpha2"
             },
             "dist": {
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/better_formats",
+                "url": "https://git.drupalcode.org/project/better_formats.git",
                 "reference": "e632735f9bec5e08db58716195edc25cc6db78b3"
             },
             "require": {
                 "reference": "e632735f9bec5e08db58716195edc25cc6db78b3"
             },
             "require": {
             "homepage": "https://www.drupal.org/project/better_formats",
             "support": {
                 "source": "http://cgit.drupalcode.org/better_formats"
             "homepage": "https://www.drupal.org/project/better_formats",
             "support": {
                 "source": "http://cgit.drupalcode.org/better_formats"
-            }
+            },
+            "time": "2018-04-24T13:52:26+00:00"
         },
         {
             "name": "drupal/blazy",
             "version": "1.0.0-rc3",
             "source": {
                 "type": "git",
         },
         {
             "name": "drupal/blazy",
             "version": "1.0.0-rc3",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/blazy",
+                "url": "https://git.drupalcode.org/project/blazy.git",
                 "reference": "8.x-1.0-rc3"
             },
             "dist": {
                 "reference": "8.x-1.0-rc3"
             },
             "dist": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/block_class",
+                "url": "https://git.drupalcode.org/project/block_class.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "3.14.0",
             "source": {
                 "type": "git",
             "version": "3.14.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/bootstrap",
+                "url": "https://git.drupalcode.org/project/bootstrap.git",
                 "reference": "8.x-3.14"
             },
             "dist": {
                 "reference": "8.x-3.14"
             },
             "dist": {
             "version": "4.2.0",
             "source": {
                 "type": "git",
             "version": "4.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/bootstrap_layouts",
+                "url": "https://git.drupalcode.org/project/bootstrap_layouts.git",
                 "reference": "8.x-4.2"
             },
             "dist": {
                 "reference": "8.x-4.2"
             },
             "dist": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/ckeditor_templates",
+                "url": "https://git.drupalcode.org/project/ckeditor_templates.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/ckeditor_widgets",
+                "url": "https://git.drupalcode.org/project/ckeditor_widgets.git",
                 "reference": "2d462637f8804b6d0b530604d0376e97a23a3b7f"
             },
             "require": {
                 "reference": "2d462637f8804b6d0b530604d0376e97a23a3b7f"
             },
             "require": {
             "version": "2.0.0-rc1",
             "source": {
                 "type": "git",
             "version": "2.0.0-rc1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/crop",
+                "url": "https://git.drupalcode.org/project/crop.git",
                 "reference": "8.x-2.0-rc1"
             },
             "dist": {
                 "reference": "8.x-2.0-rc1"
             },
             "dist": {
             "version": "3.0.0",
             "source": {
                 "type": "git",
             "version": "3.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/ctools",
+                "url": "https://git.drupalcode.org/project/ctools.git",
                 "reference": "8.x-3.0"
             },
             "dist": {
                 "reference": "8.x-3.0"
             },
             "dist": {
             "version": "1.2.0",
             "source": {
                 "type": "git",
             "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/devel",
+                "url": "https://git.drupalcode.org/project/devel.git",
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "reference": "8.x-1.2"
             },
             "dist": {
             "version": "1.0.0-rc2",
             "source": {
                 "type": "git",
             "version": "1.0.0-rc2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/diff",
+                "url": "https://git.drupalcode.org/project/diff.git",
                 "reference": "8.x-1.0-rc2"
             },
             "dist": {
                 "reference": "8.x-1.0-rc2"
             },
             "dist": {
             "version": "1.2.0",
             "source": {
                 "type": "git",
             "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/draggableviews",
+                "url": "https://git.drupalcode.org/project/draggableviews.git",
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "shasum": "0f5e9195ceec209552aa50f8ce3c230692c284db"
             },
             "require": {
                 "shasum": "0f5e9195ceec209552aa50f8ce3c230692c284db"
             },
             "require": {
-                "drupal/core": "*"
+                "drupal/core": "^8"
             },
             "require-dev": {
                 "drupal/draggableviews_demo": "*"
             },
             "type": "drupal-module",
             "extra": {
             },
             "require-dev": {
                 "drupal/draggableviews_demo": "*"
             },
             "type": "drupal-module",
             "extra": {
-                "branch-alias": {
-                    "dev-1.x": "1.x-dev"
-                },
                 "drupal": {
                     "version": "8.x-1.2",
                     "datestamp": "1541518680",
                 "drupal": {
                     "version": "8.x-1.2",
                     "datestamp": "1541518680",
             "version": "2.0.0-alpha3",
             "source": {
                 "type": "git",
             "version": "2.0.0-alpha3",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/dropzonejs",
+                "url": "https://git.drupalcode.org/project/dropzonejs.git",
                 "reference": "8.x-2.0-alpha3"
             },
             "dist": {
                 "reference": "8.x-2.0-alpha3"
             },
             "dist": {
             "version": "1.3.0",
             "source": {
                 "type": "git",
             "version": "1.3.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/drupalmoduleupgrader",
+                "url": "https://git.drupalcode.org/project/drupalmoduleupgrader.git",
                 "reference": "8.x-1.3"
             },
             "dist": {
                 "reference": "8.x-1.3"
             },
             "dist": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/embed",
+                "url": "https://git.drupalcode.org/project/embed.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "1.0.0-rc1",
             "source": {
                 "type": "git",
             "version": "1.0.0-rc1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/entity",
+                "url": "https://git.drupalcode.org/project/entity.git",
                 "reference": "8.x-1.0-rc1"
             },
             "dist": {
                 "reference": "8.x-1.0-rc1"
             },
             "dist": {
             "version": "1.6.0",
             "source": {
                 "type": "git",
             "version": "1.6.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/entity_browser",
+                "url": "https://git.drupalcode.org/project/entity_browser.git",
                 "reference": "8.x-1.6"
             },
             "dist": {
                 "reference": "8.x-1.6"
             },
             "dist": {
             "version": "1.0.0-beta2",
             "source": {
                 "type": "git",
             "version": "1.0.0-beta2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/entity_embed",
+                "url": "https://git.drupalcode.org/project/entity_embed.git",
                 "reference": "8.x-1.0-beta2"
             },
             "dist": {
                 "reference": "8.x-1.0-beta2"
             },
             "dist": {
             "version": "1.6.0",
             "source": {
                 "type": "git",
             "version": "1.6.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/entity_reference_revisions",
+                "url": "https://git.drupalcode.org/project/entity_reference_revisions.git",
                 "reference": "8.x-1.6"
             },
             "dist": {
                 "reference": "8.x-1.6"
             },
             "dist": {
             "version": "1.0.0-alpha8",
             "source": {
                 "type": "git",
             "version": "1.0.0-alpha8",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/entityqueue",
+                "url": "https://git.drupalcode.org/project/entityqueue.git",
                 "reference": "8.x-1.0-alpha8"
             },
             "dist": {
                 "reference": "8.x-1.0-alpha8"
             },
             "dist": {
             "version": "3.3.0",
             "source": {
                 "type": "git",
             "version": "3.3.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/environment_indicator",
+                "url": "https://git.drupalcode.org/project/environment_indicator.git",
                 "reference": "8.x-3.3"
             },
             "dist": {
                 "reference": "8.x-3.3"
             },
             "dist": {
             "version": "1.2.0",
             "source": {
                 "type": "git",
             "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/eu-cookie-compliance",
+                "url": "https://git.drupalcode.org/project/eu-cookie-compliance.git",
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "reference": "8.x-1.2"
             },
             "dist": {
             "version": "1.1.0",
             "source": {
                 "type": "git",
             "version": "1.1.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/file_mdm",
+                "url": "https://git.drupalcode.org/project/file_mdm.git",
                 "reference": "8.x-1.1"
             },
             "dist": {
                 "reference": "8.x-1.1"
             },
             "dist": {
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/filefield_sources",
+                "url": "https://git.drupalcode.org/project/filefield_sources.git",
                 "reference": "b19c6a839804f47587828d4a50e29e0720fa4c08"
             },
             "require": {
                 "reference": "b19c6a839804f47587828d4a50e29e0720fa4c08"
             },
             "require": {
             "homepage": "https://www.drupal.org/project/filefield_sources",
             "support": {
                 "source": "http://cgit.drupalcode.org/filefield_sources"
             "homepage": "https://www.drupal.org/project/filefield_sources",
             "support": {
                 "source": "http://cgit.drupalcode.org/filefield_sources"
-            }
+            },
+            "time": "2017-02-21T21:07:00+00:00"
         },
         {
             "name": "drupal/fontyourface",
             "version": "3.2.0",
             "source": {
                 "type": "git",
         },
         {
             "name": "drupal/fontyourface",
             "version": "3.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/fontyourface",
+                "url": "https://git.drupalcode.org/project/fontyourface.git",
                 "reference": "8.x-3.2"
             },
             "dist": {
                 "reference": "8.x-3.2"
             },
             "dist": {
             "version": "1.0.0-beta1",
             "source": {
                 "type": "git",
             "version": "1.0.0-beta1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/front",
+                "url": "https://git.drupalcode.org/project/front.git",
                 "reference": "8.x-1.0-beta1"
             },
             "dist": {
                 "reference": "8.x-1.0-beta1"
             },
             "dist": {
             "version": "2.0.0-beta2",
             "source": {
                 "type": "git",
             "version": "2.0.0-beta2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/hacked",
+                "url": "https://git.drupalcode.org/project/hacked.git",
                 "reference": "8.x-2.0-beta2"
             },
             "dist": {
                 "reference": "8.x-2.0-beta2"
             },
             "dist": {
                 "shasum": "84e018c23a39d83c2274cc009804f0abf4b9e9cb"
             },
             "require": {
                 "shasum": "84e018c23a39d83c2274cc009804f0abf4b9e9cb"
             },
             "require": {
-                "drupal/core": "*"
+                "drupal/core": "^8"
             },
             "type": "drupal-module",
             "extra": {
             },
             "type": "drupal-module",
             "extra": {
-                "branch-alias": {
-                    "dev-2.x": "2.x-dev"
-                },
                 "drupal": {
                     "version": "8.x-2.0-beta2",
                     "datestamp": "1520956980",
                 "drupal": {
                     "version": "8.x-2.0-beta2",
                     "datestamp": "1520956980",
                 {
                     "name": "Steven Jones",
                     "homepage": "https://www.drupal.org/user/99644"
                 {
                     "name": "Steven Jones",
                     "homepage": "https://www.drupal.org/user/99644"
+                },
+                {
+                    "name": "colan",
+                    "homepage": "https://www.drupal.org/user/58704"
+                },
+                {
+                    "name": "ivnish",
+                    "homepage": "https://www.drupal.org/user/3547706"
                 }
             ],
             "description": "Shows if drupal or any of its modules have been changed",
             "homepage": "https://www.drupal.org/project/hacked",
             "support": {
                 }
             ],
             "description": "Shows if drupal or any of its modules have been changed",
             "homepage": "https://www.drupal.org/project/hacked",
             "support": {
-                "source": "http://cgit.drupalcode.org/hacked"
+                "source": "https://git.drupalcode.org/project/hacked"
             }
         },
         {
             "name": "drupal/htmlawed",
             }
         },
         {
             "name": "drupal/htmlawed",
-            "version": "3.5.0",
+            "version": "3.7.0",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/htmLawed",
-                "reference": "8.x-3.5"
+                "url": "https://git.drupalcode.org/project/htmLawed.git",
+                "reference": "8.x-3.7"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/htmlawed-8.x-3.5.zip",
-                "reference": "8.x-3.5",
-                "shasum": "48cf7dda2d327fcc2024273a5b37861872e0f53f"
+                "url": "https://ftp.drupal.org/files/projects/htmlawed-8.x-3.7.zip",
+                "reference": "8.x-3.7",
+                "shasum": "f3b49eb425831947e3069369aecd5b32a27ac6cb"
             },
             "require": {
                 "drupal/core": "~8.0"
             },
             "type": "drupal-module",
             "extra": {
             },
             "require": {
                 "drupal/core": "~8.0"
             },
             "type": "drupal-module",
             "extra": {
-                "branch-alias": {
-                    "dev-3.x": "3.x-dev"
-                },
                 "drupal": {
                 "drupal": {
-                    "version": "8.x-3.5",
-                    "datestamp": "1530751724",
+                    "version": "8.x-3.7",
+                    "datestamp": "1586586866",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
             "description": "Use htmLawed to restrict and correct HTML for compliance with admin. policy and standards and for security",
             "homepage": "https://www.drupal.org/project/htmlawed",
             "support": {
             "description": "Use htmLawed to restrict and correct HTML for compliance with admin. policy and standards and for security",
             "homepage": "https://www.drupal.org/project/htmlawed",
             "support": {
-                "source": "http://cgit.drupalcode.org/htmlawed"
+                "source": "https://git.drupalcode.org/project/htmlawed"
             }
         },
         {
             }
         },
         {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/http2_server_push",
+                "url": "https://git.drupalcode.org/project/http2_server_push.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "2.2.0",
             "source": {
                 "type": "git",
             "version": "2.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/image_widget_crop",
+                "url": "https://git.drupalcode.org/project/image_widget_crop.git",
                 "reference": "8.x-2.2"
             },
             "dist": {
                 "reference": "8.x-2.2"
             },
             "dist": {
             "version": "2.3.0",
             "source": {
                 "type": "git",
             "version": "2.3.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/imagemagick",
+                "url": "https://git.drupalcode.org/project/imagemagick.git",
                 "reference": "8.x-2.3"
             },
             "dist": {
                 "reference": "8.x-2.3"
             },
             "dist": {
             "version": "1.0.0-rc1",
             "source": {
                 "type": "git",
             "version": "1.0.0-rc1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/inline_entity_form",
+                "url": "https://git.drupalcode.org/project/inline_entity_form.git",
                 "reference": "8.x-1.0-rc1"
             },
             "dist": {
                 "reference": "8.x-1.0-rc1"
             },
             "dist": {
             "version": "1.0.0-alpha23",
             "source": {
                 "type": "git",
             "version": "1.0.0-alpha23",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/layout_plugin",
+                "url": "https://git.drupalcode.org/project/layout_plugin.git",
                 "reference": "8.x-1.0-alpha23"
             },
             "dist": {
                 "reference": "8.x-1.0-alpha23"
             },
             "dist": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/layouter",
+                "url": "https://git.drupalcode.org/project/layouter.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "3.0.0-alpha1",
             "source": {
                 "type": "git",
             "version": "3.0.0-alpha1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/libraries",
+                "url": "https://git.drupalcode.org/project/libraries.git",
                 "reference": "8.x-3.0-alpha1"
             },
             "dist": {
                 "reference": "8.x-3.0-alpha1"
             },
             "dist": {
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/linkchecker",
+                "url": "https://git.drupalcode.org/project/linkchecker.git",
                 "reference": "f59edc88741c60991526dc54adc89554c0ca571b"
             },
             "require": {
                 "reference": "f59edc88741c60991526dc54adc89554c0ca571b"
             },
             "require": {
             "version": "4.3.0",
             "source": {
                 "type": "git",
             "version": "4.3.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/linkit",
+                "url": "https://git.drupalcode.org/project/linkit.git",
                 "reference": "8.x-4.3"
             },
             "dist": {
                 "reference": "8.x-4.3"
             },
             "dist": {
             "version": "1.0.0-alpha2",
             "source": {
                 "type": "git",
             "version": "1.0.0-alpha2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/media_entity_actions",
+                "url": "https://git.drupalcode.org/project/media_entity_actions.git",
                 "reference": "8.x-1.0-alpha2"
             },
             "dist": {
                 "reference": "8.x-1.0-alpha2"
             },
             "dist": {
             "version": "2.0.0-alpha2",
             "source": {
                 "type": "git",
             "version": "2.0.0-alpha2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/media_entity_instagram",
+                "url": "https://git.drupalcode.org/project/media_entity_instagram.git",
                 "reference": "8.x-2.0-alpha2"
             },
             "dist": {
                 "reference": "8.x-2.0-alpha2"
             },
             "dist": {
             "version": "2.0.0-alpha1",
             "source": {
                 "type": "git",
             "version": "2.0.0-alpha1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/media_entity_slideshow",
+                "url": "https://git.drupalcode.org/project/media_entity_slideshow.git",
                 "reference": "8.x-2.0-alpha1"
             },
             "dist": {
                 "reference": "8.x-2.0-alpha1"
             },
             "dist": {
             "version": "2.0.0-alpha2",
             "source": {
                 "type": "git",
             "version": "2.0.0-alpha2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/media_entity_twitter",
+                "url": "https://git.drupalcode.org/project/media_entity_twitter.git",
                 "reference": "8.x-2.0-alpha2"
             },
             "dist": {
                 "reference": "8.x-2.0-alpha2"
             },
             "dist": {
             "version": "2.0.0",
             "source": {
                 "type": "git",
             "version": "2.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/memcache",
+                "url": "https://git.drupalcode.org/project/memcache.git",
                 "reference": "8.x-2.0"
             },
             "dist": {
                 "reference": "8.x-2.0"
             },
             "dist": {
             "version": "1.7.0",
             "source": {
                 "type": "git",
             "version": "1.7.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/metatag",
+                "url": "https://git.drupalcode.org/project/metatag.git",
                 "reference": "8.x-1.7"
             },
             "dist": {
                 "reference": "8.x-1.7"
             },
             "dist": {
             "version": "4.0.0",
             "source": {
                 "type": "git",
             "version": "4.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/migrate_plus",
+                "url": "https://git.drupalcode.org/project/migrate_plus.git",
                 "reference": "8.x-4.0"
             },
             "dist": {
                 "reference": "8.x-4.0"
             },
             "dist": {
             "version": "4.0.0",
             "source": {
                 "type": "git",
             "version": "4.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/migrate_tools",
+                "url": "https://git.drupalcode.org/project/migrate_tools.git",
                 "reference": "8.x-4.0"
             },
             "dist": {
                 "reference": "8.x-4.0"
             },
             "dist": {
             "version": "3.0.0-rc5",
             "source": {
                 "type": "git",
             "version": "3.0.0-rc5",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/migrate_upgrade",
+                "url": "https://git.drupalcode.org/project/migrate_upgrade.git",
                 "reference": "8.x-3.0-rc5"
             },
             "dist": {
                 "reference": "8.x-3.0-rc5"
             },
             "dist": {
             "version": "1.3.0",
             "source": {
                 "type": "git",
             "version": "1.3.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/pathauto",
+                "url": "https://git.drupalcode.org/project/pathauto.git",
                 "reference": "8.x-1.3"
             },
             "dist": {
                 "reference": "8.x-1.3"
             },
             "dist": {
             "version": "1.0.0-alpha1",
             "source": {
                 "type": "git",
             "version": "1.0.0-alpha1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/pathologic",
+                "url": "https://git.drupalcode.org/project/pathologic.git",
                 "reference": "8.x-1.0-alpha1"
             },
             "dist": {
                 "reference": "8.x-1.0-alpha1"
             },
             "dist": {
             "version": "1.61.0",
             "source": {
                 "type": "git",
             "version": "1.61.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/permissions_by_term",
+                "url": "https://git.drupalcode.org/project/permissions_by_term.git",
                 "reference": "8.x-1.61"
             },
             "dist": {
                 "reference": "8.x-1.61"
             },
             "dist": {
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/php",
+                "url": "https://git.drupalcode.org/project/php.git",
                 "reference": "e5c1c4047f5f1522e5d630bca93d50c61ef6a2c0"
             },
             "require": {
                 "reference": "e5c1c4047f5f1522e5d630bca93d50c61ef6a2c0"
             },
             "require": {
             "version": "1.3.0",
             "source": {
                 "type": "git",
             "version": "1.3.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/redirect",
+                "url": "https://git.drupalcode.org/project/redirect.git",
                 "reference": "8.x-1.3"
             },
             "dist": {
                 "reference": "8.x-1.3"
             },
             "dist": {
                 "source": "http://cgit.drupalcode.org/redirect"
             }
         },
                 "source": "http://cgit.drupalcode.org/redirect"
             }
         },
-        {
-            "name": "drupal/security_review",
-            "version": "dev-1.x",
-            "source": {
-                "type": "git",
-                "url": "https://git.drupal.org/project/security_review",
-                "reference": "9b8a34a21cac85913845df4eebb9a05c69de82d8"
-            },
-            "require": {
-                "drupal/core": "~8.0"
-            },
-            "type": "drupal-module",
-            "extra": {
-                "branch-alias": {
-                    "dev-1.x": "1.x-dev"
-                },
-                "drupal": {
-                    "version": "8.x-1.x-dev",
-                    "datestamp": "1532558881",
-                    "security-coverage": {
-                        "status": "not-covered",
-                        "message": "Dev releases are not covered by Drupal security advisories."
-                    }
-                },
-                "patches_applied": []
-            },
-            "notification-url": "https://packages.drupal.org/8/downloads",
-            "license": [
-                "GPL-2.0-or-later"
-            ],
-            "authors": [
-                {
-                    "name": "banviktor",
-                    "homepage": "https://www.drupal.org/user/3176333"
-                },
-                {
-                    "name": "coltrane",
-                    "homepage": "https://www.drupal.org/user/91990"
-                },
-                {
-                    "name": "dsnopek",
-                    "homepage": "https://www.drupal.org/user/266527"
-                },
-                {
-                    "name": "greggles",
-                    "homepage": "https://www.drupal.org/user/36762"
-                }
-            ],
-            "description": "Site security and configuration review module.",
-            "homepage": "https://www.drupal.org/project/security_review",
-            "support": {
-                "source": "http://cgit.drupalcode.org/security_review"
-            },
-            "time": "2018-07-27T02:32:58+00:00"
-        },
         {
             "name": "drupal/simple_sitemap",
             "version": "2.12.0",
             "source": {
                 "type": "git",
         {
             "name": "drupal/simple_sitemap",
             "version": "2.12.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/simple_sitemap",
+                "url": "https://git.drupalcode.org/project/simple_sitemap.git",
                 "reference": "8.x-2.12"
             },
             "dist": {
                 "reference": "8.x-2.12"
             },
             "dist": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/slick",
+                "url": "https://git.drupalcode.org/project/slick.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "2.0.0-alpha2",
             "source": {
                 "type": "git",
             "version": "2.0.0-alpha2",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/slick_media",
+                "url": "https://git.drupalcode.org/project/slick_media.git",
                 "reference": "8.x-2.0-alpha2"
             },
             "dist": {
                 "reference": "8.x-2.0-alpha2"
             },
             "dist": {
             "version": "1.2.0",
             "source": {
                 "type": "git",
             "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/superfish",
+                "url": "https://git.drupalcode.org/project/superfish.git",
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "reference": "8.x-1.2"
             },
             "dist": {
             "version": "1.1.0",
             "source": {
                 "type": "git",
             "version": "1.1.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/toc_formatter",
+                "url": "https://git.drupalcode.org/project/toc_formatter.git",
                 "reference": "8.x-1.1"
             },
             "dist": {
                 "reference": "8.x-1.1"
             },
             "dist": {
             "version": "1.2.0",
             "source": {
                 "type": "git",
             "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/tocify",
+                "url": "https://git.drupalcode.org/project/tocify.git",
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "reference": "8.x-1.2"
             },
             "dist": {
             "version": "1.5.0",
             "source": {
                 "type": "git",
             "version": "1.5.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/token",
+                "url": "https://git.drupalcode.org/project/token.git",
                 "reference": "8.x-1.5"
             },
             "dist": {
                 "reference": "8.x-1.5"
             },
             "dist": {
             "version": "1.0.0-alpha1",
             "source": {
                 "type": "git",
             "version": "1.0.0-alpha1",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/typogrify",
+                "url": "https://git.drupalcode.org/project/typogrify.git",
                 "reference": "8.x-1.0-alpha1"
             },
             "dist": {
                 "reference": "8.x-1.0-alpha1"
             },
             "dist": {
             "version": "1.2.0",
             "source": {
                 "type": "git",
             "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/video",
+                "url": "https://git.drupalcode.org/project/video.git",
                 "reference": "8.x-1.2"
             },
             "dist": {
                 "reference": "8.x-1.2"
             },
             "dist": {
             "version": "2.0.0",
             "source": {
                 "type": "git",
             "version": "2.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/video_embed_field",
+                "url": "https://git.drupalcode.org/project/video_embed_field.git",
                 "reference": "8.x-2.0"
             },
             "dist": {
                 "reference": "8.x-2.0"
             },
             "dist": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/videojs",
+                "url": "https://git.drupalcode.org/project/videojs.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "3.1.0",
             "source": {
                 "type": "git",
             "version": "3.1.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/views_bootstrap",
+                "url": "https://git.drupalcode.org/project/views_bootstrap.git",
                 "reference": "8.x-3.1"
             },
             "dist": {
                 "reference": "8.x-3.1"
             },
             "dist": {
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/views_responsive_grid",
+                "url": "https://git.drupalcode.org/project/views_responsive_grid.git",
                 "reference": "b8478ccf4cb6dc6837a0c1170a848e418499a357"
             },
             "require": {
                 "reference": "b8478ccf4cb6dc6837a0c1170a848e418499a357"
             },
             "require": {
             "keywords": [
                 "Drush"
             ],
             "keywords": [
                 "Drush"
             ],
+            "abandoned": true,
             "time": "2015-10-16T21:32:27+00:00"
         },
         {
             "time": "2015-10-16T21:32:27+00:00"
         },
         {
             "version": "0.9.1",
             "source": {
                 "type": "git",
             "version": "0.9.1",
             "source": {
                 "type": "git",
-                "url": "https://github.com/njh/easyrdf.git",
+                "url": "https://github.com/easyrdf/easyrdf.git",
                 "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566"
             },
             "dist": {
                 "type": "zip",
                 "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/njh/easyrdf/zipball/acd09dfe0555fbcfa254291e433c45fdd4652566",
+                "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/acd09dfe0555fbcfa254291e433c45fdd4652566",
                 "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566",
                 "shasum": ""
             },
                 "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566",
                 "shasum": ""
             },
             "version": "dev-master",
             "source": {
                 "type": "git",
             "version": "dev-master",
             "source": {
                 "type": "git",
-                "url": "https://github.com/grom358/pharborist.git",
+                "url": "git@github.com:grom358/pharborist.git",
                 "reference": "0db9e51299a80e95b06857ed1809f59bbbab1af6"
             },
             "dist": {
                 "reference": "0db9e51299a80e95b06857ed1809f59bbbab1af6"
             },
             "dist": {
                     "email": "jakub.onderka@gmail.com"
                 }
             ],
                     "email": "jakub.onderka@gmail.com"
                 }
             ],
+            "abandoned": "php-parallel-lint/php-console-color",
             "time": "2018-09-29T17:23:10+00:00"
         },
         {
             "time": "2018-09-29T17:23:10+00:00"
         },
         {
                 }
             ],
             "description": "Highlight PHP code in terminal",
                 }
             ],
             "description": "Highlight PHP code in terminal",
+            "abandoned": "php-parallel-lint/php-console-highlighter",
             "time": "2018-09-29T18:48:56+00:00"
         },
         {
             "time": "2018-09-29T18:48:56+00:00"
         },
         {
             "version": "1.3.0",
             "source": {
                 "type": "git",
             "version": "1.3.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/webmozart/assert.git",
+                "url": "https://github.com/webmozarts/assert.git",
                 "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
             },
             "dist": {
                 "type": "zip",
                 "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
+                "url": "https://api.github.com/repos/webmozarts/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
                 "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
                 "shasum": ""
             },
                 "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
                 "shasum": ""
             },
                 "psr",
                 "psr-7"
             ],
                 "psr",
                 "psr-7"
             ],
+            "abandoned": "laminas/laminas-diactoros",
             "time": "2018-09-05T19:29:37+00:00"
         },
         {
             "time": "2018-09-05T19:29:37+00:00"
         },
         {
                 "escaper",
                 "zf"
             ],
                 "escaper",
                 "zf"
             ],
+            "abandoned": "laminas/laminas-escaper",
             "time": "2018-04-25T15:48:53+00:00"
         },
         {
             "time": "2018-04-25T15:48:53+00:00"
         },
         {
                 "feed",
                 "zf"
             ],
                 "feed",
                 "zf"
             ],
+            "abandoned": "laminas/laminas-feed",
             "time": "2018-08-01T13:53:20+00:00"
         },
         {
             "time": "2018-08-01T13:53:20+00:00"
         },
         {
                 "stdlib",
                 "zf"
             ],
                 "stdlib",
                 "zf"
             ],
+            "abandoned": "laminas/laminas-stdlib",
             "time": "2018-08-28T21:34:05+00:00"
         }
     ],
             "time": "2018-08-28T21:34:05+00:00"
         }
     ],
             "version": "dev-1.x",
             "source": {
                 "type": "git",
             "version": "dev-1.x",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/livereload",
+                "url": "https://git.drupalcode.org/project/livereload.git",
                 "reference": "223feb798d2af436818c3d8fd0b47718569ebd4b"
             },
             "require": {
                 "reference": "223feb798d2af436818c3d8fd0b47718569ebd4b"
             },
             "require": {
             "version": "1.0.0",
             "source": {
                 "type": "git",
             "version": "1.0.0",
             "source": {
                 "type": "git",
-                "url": "https://git.drupal.org/project/twig_xdebug",
+                "url": "https://git.drupalcode.org/project/twig_xdebug.git",
                 "reference": "8.x-1.0"
             },
             "dist": {
                 "reference": "8.x-1.0"
             },
             "dist": {
             "version": "v1.6.5",
             "source": {
                 "type": "git",
             "version": "v1.6.5",
             "source": {
                 "type": "git",
-                "url": "https://github.com/mikey179/vfsStream.git",
+                "url": "https://github.com/bovigo/vfsStream.git",
                 "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
             },
             "dist": {
                 "type": "zip",
                 "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
+                "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
                 "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
                 "shasum": ""
             },
                 "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
                 "shasum": ""
             },
             "keywords": [
                 "tokenizer"
             ],
             "keywords": [
                 "tokenizer"
             ],
+            "abandoned": true,
             "time": "2017-12-04T08:55:13+00:00"
         },
         {
             "time": "2017-12-04T08:55:13+00:00"
         },
         {
                 "mock",
                 "xunit"
             ],
                 "mock",
                 "xunit"
             ],
+            "abandoned": true,
             "time": "2015-10-02T06:51:40+00:00"
         },
         {
             "time": "2015-10-02T06:51:40+00:00"
         },
         {
         "drupal/inline_entity_form": 10,
         "drupal/entity_embed": 10,
         "drupal/dropzonejs": 15,
         "drupal/inline_entity_form": 10,
         "drupal/entity_embed": 10,
         "drupal/dropzonejs": 15,
-        "drupal/security_review": 20,
         "drupal/livereload": 20
     },
     "prefer-stable": true,
         "drupal/livereload": 20
     },
     "prefer-stable": true,
     "platform-dev": [],
     "platform-overrides": {
         "php": "7.0.30"
     "platform-dev": [],
     "platform-overrides": {
         "php": "7.0.30"
-    }
+    },
+    "plugin-api-version": "1.1.0"
 }
 }
index fce8549f0781bafdc7da2301b84d048286757445..03b9bb9c40cb86c2c2bbec2ce6ff0ddce9ad586c 100644 (file)
@@ -60,7 +60,7 @@ class ClassLoader
     public function getPrefixes()
     {
         if (!empty($this->prefixesPsr0)) {
     public function getPrefixes()
     {
         if (!empty($this->prefixesPsr0)) {
-            return call_user_func_array('array_merge', $this->prefixesPsr0);
+            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
         }
 
         return array();
         }
 
         return array();
index e0c489e86d64554d50a85b9513f93e49963fe2ae..2bab8ce2c7e065df2e4184f36d4fa73c5760bf0a 100644 (file)
@@ -13,6 +13,9 @@ class ComposerAutoloaderInit045d6a3105edf51cf91c16e965235549
         }
     }
 
         }
     }
 
+    /**
+     * @return \Composer\Autoload\ClassLoader
+     */
     public static function getLoader()
     {
         if (null !== self::$loader) {
     public static function getLoader()
     {
         if (null !== self::$loader) {
index 4240b09b1147c94781cce3b17deb9f3baa20ee43..c65055a1cf99a04a1112ee83a8966698720df545 100644 (file)
             "MIT"
         ],
         "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
             "MIT"
         ],
         "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
-        "homepage": "https://github.com/container-interop/container-interop"
+        "homepage": "https://github.com/container-interop/container-interop",
+        "abandoned": "psr/container"
     },
     {
         "name": "cweagans/composer-patches",
     },
     {
         "name": "cweagans/composer-patches",
         "license": [
             "GPL-2.0-or-later"
         ],
         "license": [
             "GPL-2.0-or-later"
         ],
-        "description": "Composer Plugin for updating the Drupal scaffold files when using drupal/core"
+        "description": "Composer Plugin for updating the Drupal scaffold files when using drupal/core",
+        "abandoned": "drupal/core-composer-scaffold"
     },
     {
         "name": "drupal/admin_toolbar",
     },
     {
         "name": "drupal/admin_toolbar",
         "version_normalized": "1.24.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.24.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/admin_toolbar",
+            "url": "https://git.drupalcode.org/project/admin_toolbar.git",
             "reference": "8.x-1.24"
         },
         "dist": {
             "reference": "8.x-1.24"
         },
         "dist": {
         "version_normalized": "2.4.0.0",
         "source": {
             "type": "git",
         "version_normalized": "2.4.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/advagg",
+            "url": "https://git.drupalcode.org/project/advagg.git",
             "reference": "8.x-2.4"
         },
         "dist": {
             "reference": "8.x-2.4"
         },
         "dist": {
         "version_normalized": "1.0.0.0-alpha2",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-alpha2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/advanced_help",
+            "url": "https://git.drupalcode.org/project/advanced_help.git",
             "reference": "8.x-1.0-alpha2"
         },
         "dist": {
             "reference": "8.x-1.0-alpha2"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/better_formats",
+            "url": "https://git.drupalcode.org/project/better_formats.git",
             "reference": "e632735f9bec5e08db58716195edc25cc6db78b3"
         },
         "require": {
             "reference": "e632735f9bec5e08db58716195edc25cc6db78b3"
         },
         "require": {
         "version_normalized": "1.0.0.0-RC3",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-RC3",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/blazy",
+            "url": "https://git.drupalcode.org/project/blazy.git",
             "reference": "8.x-1.0-rc3"
         },
         "dist": {
             "reference": "8.x-1.0-rc3"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/block_class",
+            "url": "https://git.drupalcode.org/project/block_class.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "3.14.0.0",
         "source": {
             "type": "git",
         "version_normalized": "3.14.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/bootstrap",
+            "url": "https://git.drupalcode.org/project/bootstrap.git",
             "reference": "8.x-3.14"
         },
         "dist": {
             "reference": "8.x-3.14"
         },
         "dist": {
         "version_normalized": "4.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "4.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/bootstrap_layouts",
+            "url": "https://git.drupalcode.org/project/bootstrap_layouts.git",
             "reference": "8.x-4.2"
         },
         "dist": {
             "reference": "8.x-4.2"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/ckeditor_templates",
+            "url": "https://git.drupalcode.org/project/ckeditor_templates.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/ckeditor_widgets",
+            "url": "https://git.drupalcode.org/project/ckeditor_widgets.git",
             "reference": "2d462637f8804b6d0b530604d0376e97a23a3b7f"
         },
         "require": {
             "reference": "2d462637f8804b6d0b530604d0376e97a23a3b7f"
         },
         "require": {
         "version_normalized": "2.0.0.0-RC1",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-RC1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/crop",
+            "url": "https://git.drupalcode.org/project/crop.git",
             "reference": "8.x-2.0-rc1"
         },
         "dist": {
             "reference": "8.x-2.0-rc1"
         },
         "dist": {
         "version_normalized": "3.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "3.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/ctools",
+            "url": "https://git.drupalcode.org/project/ctools.git",
             "reference": "8.x-3.0"
         },
         "dist": {
             "reference": "8.x-3.0"
         },
         "dist": {
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/devel",
+            "url": "https://git.drupalcode.org/project/devel.git",
             "reference": "8.x-1.2"
         },
         "dist": {
             "reference": "8.x-1.2"
         },
         "dist": {
         "version_normalized": "1.0.0.0-RC2",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-RC2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/diff",
+            "url": "https://git.drupalcode.org/project/diff.git",
             "reference": "8.x-1.0-rc2"
         },
         "dist": {
             "reference": "8.x-1.0-rc2"
         },
         "dist": {
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/draggableviews",
+            "url": "https://git.drupalcode.org/project/draggableviews.git",
             "reference": "8.x-1.2"
         },
         "dist": {
             "reference": "8.x-1.2"
         },
         "dist": {
             "shasum": "0f5e9195ceec209552aa50f8ce3c230692c284db"
         },
         "require": {
             "shasum": "0f5e9195ceec209552aa50f8ce3c230692c284db"
         },
         "require": {
-            "drupal/core": "*"
+            "drupal/core": "^8"
         },
         "require-dev": {
             "drupal/draggableviews_demo": "*"
         },
         "type": "drupal-module",
         "extra": {
         },
         "require-dev": {
             "drupal/draggableviews_demo": "*"
         },
         "type": "drupal-module",
         "extra": {
-            "branch-alias": {
-                "dev-1.x": "1.x-dev"
-            },
             "drupal": {
                 "version": "8.x-1.2",
                 "datestamp": "1541518680",
             "drupal": {
                 "version": "8.x-1.2",
                 "datestamp": "1541518680",
         "version_normalized": "2.0.0.0-alpha3",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-alpha3",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/dropzonejs",
+            "url": "https://git.drupalcode.org/project/dropzonejs.git",
             "reference": "8.x-2.0-alpha3"
         },
         "dist": {
             "reference": "8.x-2.0-alpha3"
         },
         "dist": {
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/drupalmoduleupgrader",
+            "url": "https://git.drupalcode.org/project/drupalmoduleupgrader.git",
             "reference": "8.x-1.3"
         },
         "dist": {
             "reference": "8.x-1.3"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/embed",
+            "url": "https://git.drupalcode.org/project/embed.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "1.0.0.0-RC1",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-RC1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/entity",
+            "url": "https://git.drupalcode.org/project/entity.git",
             "reference": "8.x-1.0-rc1"
         },
         "dist": {
             "reference": "8.x-1.0-rc1"
         },
         "dist": {
         "version_normalized": "1.6.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.6.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/entity_browser",
+            "url": "https://git.drupalcode.org/project/entity_browser.git",
             "reference": "8.x-1.6"
         },
         "dist": {
             "reference": "8.x-1.6"
         },
         "dist": {
         "version_normalized": "1.0.0.0-beta2",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-beta2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/entity_embed",
+            "url": "https://git.drupalcode.org/project/entity_embed.git",
             "reference": "8.x-1.0-beta2"
         },
         "dist": {
             "reference": "8.x-1.0-beta2"
         },
         "dist": {
         "version_normalized": "1.6.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.6.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/entity_reference_revisions",
+            "url": "https://git.drupalcode.org/project/entity_reference_revisions.git",
             "reference": "8.x-1.6"
         },
         "dist": {
             "reference": "8.x-1.6"
         },
         "dist": {
         "version_normalized": "1.0.0.0-alpha8",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-alpha8",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/entityqueue",
+            "url": "https://git.drupalcode.org/project/entityqueue.git",
             "reference": "8.x-1.0-alpha8"
         },
         "dist": {
             "reference": "8.x-1.0-alpha8"
         },
         "dist": {
         "version_normalized": "3.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "3.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/environment_indicator",
+            "url": "https://git.drupalcode.org/project/environment_indicator.git",
             "reference": "8.x-3.3"
         },
         "dist": {
             "reference": "8.x-3.3"
         },
         "dist": {
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/eu-cookie-compliance",
+            "url": "https://git.drupalcode.org/project/eu-cookie-compliance.git",
             "reference": "8.x-1.2"
         },
         "dist": {
             "reference": "8.x-1.2"
         },
         "dist": {
         "version_normalized": "1.1.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.1.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/file_mdm",
+            "url": "https://git.drupalcode.org/project/file_mdm.git",
             "reference": "8.x-1.1"
         },
         "dist": {
             "reference": "8.x-1.1"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/filefield_sources",
+            "url": "https://git.drupalcode.org/project/filefield_sources.git",
             "reference": "b19c6a839804f47587828d4a50e29e0720fa4c08"
         },
         "require": {
             "reference": "b19c6a839804f47587828d4a50e29e0720fa4c08"
         },
         "require": {
         "version_normalized": "3.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "3.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/fontyourface",
+            "url": "https://git.drupalcode.org/project/fontyourface.git",
             "reference": "8.x-3.2"
         },
         "dist": {
             "reference": "8.x-3.2"
         },
         "dist": {
         "version_normalized": "1.0.0.0-beta1",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-beta1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/front",
+            "url": "https://git.drupalcode.org/project/front.git",
             "reference": "8.x-1.0-beta1"
         },
         "dist": {
             "reference": "8.x-1.0-beta1"
         },
         "dist": {
         "version_normalized": "2.0.0.0-beta2",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-beta2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/hacked",
+            "url": "https://git.drupalcode.org/project/hacked.git",
             "reference": "8.x-2.0-beta2"
         },
         "dist": {
             "reference": "8.x-2.0-beta2"
         },
         "dist": {
             "shasum": "84e018c23a39d83c2274cc009804f0abf4b9e9cb"
         },
         "require": {
             "shasum": "84e018c23a39d83c2274cc009804f0abf4b9e9cb"
         },
         "require": {
-            "drupal/core": "*"
+            "drupal/core": "^8"
         },
         "type": "drupal-module",
         "extra": {
         },
         "type": "drupal-module",
         "extra": {
-            "branch-alias": {
-                "dev-2.x": "2.x-dev"
-            },
             "drupal": {
                 "version": "8.x-2.0-beta2",
                 "datestamp": "1520956980",
             "drupal": {
                 "version": "8.x-2.0-beta2",
                 "datestamp": "1520956980",
             {
                 "name": "Steven Jones",
                 "homepage": "https://www.drupal.org/user/99644"
             {
                 "name": "Steven Jones",
                 "homepage": "https://www.drupal.org/user/99644"
+            },
+            {
+                "name": "colan",
+                "homepage": "https://www.drupal.org/user/58704"
+            },
+            {
+                "name": "ivnish",
+                "homepage": "https://www.drupal.org/user/3547706"
             }
         ],
         "description": "Shows if drupal or any of its modules have been changed",
         "homepage": "https://www.drupal.org/project/hacked",
         "support": {
             }
         ],
         "description": "Shows if drupal or any of its modules have been changed",
         "homepage": "https://www.drupal.org/project/hacked",
         "support": {
-            "source": "http://cgit.drupalcode.org/hacked"
+            "source": "https://git.drupalcode.org/project/hacked"
         }
     },
     {
         "name": "drupal/htmlawed",
         }
     },
     {
         "name": "drupal/htmlawed",
-        "version": "3.5.0",
-        "version_normalized": "3.5.0.0",
+        "version": "3.7.0",
+        "version_normalized": "3.7.0.0",
         "source": {
             "type": "git",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/htmLawed",
-            "reference": "8.x-3.5"
+            "url": "https://git.drupalcode.org/project/htmLawed.git",
+            "reference": "8.x-3.7"
         },
         "dist": {
             "type": "zip",
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/htmlawed-8.x-3.5.zip",
-            "reference": "8.x-3.5",
-            "shasum": "48cf7dda2d327fcc2024273a5b37861872e0f53f"
+            "url": "https://ftp.drupal.org/files/projects/htmlawed-8.x-3.7.zip",
+            "reference": "8.x-3.7",
+            "shasum": "f3b49eb425831947e3069369aecd5b32a27ac6cb"
         },
         "require": {
             "drupal/core": "~8.0"
         },
         "type": "drupal-module",
         "extra": {
         },
         "require": {
             "drupal/core": "~8.0"
         },
         "type": "drupal-module",
         "extra": {
-            "branch-alias": {
-                "dev-3.x": "3.x-dev"
-            },
             "drupal": {
             "drupal": {
-                "version": "8.x-3.5",
-                "datestamp": "1530751724",
+                "version": "8.x-3.7",
+                "datestamp": "1586586866",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
         "description": "Use htmLawed to restrict and correct HTML for compliance with admin. policy and standards and for security",
         "homepage": "https://www.drupal.org/project/htmlawed",
         "support": {
         "description": "Use htmLawed to restrict and correct HTML for compliance with admin. policy and standards and for security",
         "homepage": "https://www.drupal.org/project/htmlawed",
         "support": {
-            "source": "http://cgit.drupalcode.org/htmlawed"
+            "source": "https://git.drupalcode.org/project/htmlawed"
         }
     },
     {
         }
     },
     {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/http2_server_push",
+            "url": "https://git.drupalcode.org/project/http2_server_push.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "2.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "2.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/image_widget_crop",
+            "url": "https://git.drupalcode.org/project/image_widget_crop.git",
             "reference": "8.x-2.2"
         },
         "dist": {
             "reference": "8.x-2.2"
         },
         "dist": {
         "version_normalized": "2.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "2.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/imagemagick",
+            "url": "https://git.drupalcode.org/project/imagemagick.git",
             "reference": "8.x-2.3"
         },
         "dist": {
             "reference": "8.x-2.3"
         },
         "dist": {
         "version_normalized": "1.0.0.0-RC1",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-RC1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/inline_entity_form",
+            "url": "https://git.drupalcode.org/project/inline_entity_form.git",
             "reference": "8.x-1.0-rc1"
         },
         "dist": {
             "reference": "8.x-1.0-rc1"
         },
         "dist": {
         "version_normalized": "1.0.0.0-alpha23",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-alpha23",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/layout_plugin",
+            "url": "https://git.drupalcode.org/project/layout_plugin.git",
             "reference": "8.x-1.0-alpha23"
         },
         "dist": {
             "reference": "8.x-1.0-alpha23"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/layouter",
+            "url": "https://git.drupalcode.org/project/layouter.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "3.0.0.0-alpha1",
         "source": {
             "type": "git",
         "version_normalized": "3.0.0.0-alpha1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/libraries",
+            "url": "https://git.drupalcode.org/project/libraries.git",
             "reference": "8.x-3.0-alpha1"
         },
         "dist": {
             "reference": "8.x-3.0-alpha1"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/linkchecker",
+            "url": "https://git.drupalcode.org/project/linkchecker.git",
             "reference": "f59edc88741c60991526dc54adc89554c0ca571b"
         },
         "require": {
             "reference": "f59edc88741c60991526dc54adc89554c0ca571b"
         },
         "require": {
         "version_normalized": "4.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "4.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/linkit",
+            "url": "https://git.drupalcode.org/project/linkit.git",
             "reference": "8.x-4.3"
         },
         "dist": {
             "reference": "8.x-4.3"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/livereload",
+            "url": "https://git.drupalcode.org/project/livereload.git",
             "reference": "223feb798d2af436818c3d8fd0b47718569ebd4b"
         },
         "require": {
             "reference": "223feb798d2af436818c3d8fd0b47718569ebd4b"
         },
         "require": {
         "version_normalized": "1.0.0.0-alpha2",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-alpha2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/media_entity_actions",
+            "url": "https://git.drupalcode.org/project/media_entity_actions.git",
             "reference": "8.x-1.0-alpha2"
         },
         "dist": {
             "reference": "8.x-1.0-alpha2"
         },
         "dist": {
         "version_normalized": "2.0.0.0-alpha2",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-alpha2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/media_entity_instagram",
+            "url": "https://git.drupalcode.org/project/media_entity_instagram.git",
             "reference": "8.x-2.0-alpha2"
         },
         "dist": {
             "reference": "8.x-2.0-alpha2"
         },
         "dist": {
         "version_normalized": "2.0.0.0-alpha1",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-alpha1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/media_entity_slideshow",
+            "url": "https://git.drupalcode.org/project/media_entity_slideshow.git",
             "reference": "8.x-2.0-alpha1"
         },
         "dist": {
             "reference": "8.x-2.0-alpha1"
         },
         "dist": {
         "version_normalized": "2.0.0.0-alpha2",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-alpha2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/media_entity_twitter",
+            "url": "https://git.drupalcode.org/project/media_entity_twitter.git",
             "reference": "8.x-2.0-alpha2"
         },
         "dist": {
             "reference": "8.x-2.0-alpha2"
         },
         "dist": {
         "version_normalized": "2.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/memcache",
+            "url": "https://git.drupalcode.org/project/memcache.git",
             "reference": "8.x-2.0"
         },
         "dist": {
             "reference": "8.x-2.0"
         },
         "dist": {
         "version_normalized": "1.7.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.7.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/metatag",
+            "url": "https://git.drupalcode.org/project/metatag.git",
             "reference": "8.x-1.7"
         },
         "dist": {
             "reference": "8.x-1.7"
         },
         "dist": {
         "version_normalized": "4.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "4.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/migrate_plus",
+            "url": "https://git.drupalcode.org/project/migrate_plus.git",
             "reference": "8.x-4.0"
         },
         "dist": {
             "reference": "8.x-4.0"
         },
         "dist": {
         "version_normalized": "4.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "4.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/migrate_tools",
+            "url": "https://git.drupalcode.org/project/migrate_tools.git",
             "reference": "8.x-4.0"
         },
         "dist": {
             "reference": "8.x-4.0"
         },
         "dist": {
         "version_normalized": "3.0.0.0-RC5",
         "source": {
             "type": "git",
         "version_normalized": "3.0.0.0-RC5",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/migrate_upgrade",
+            "url": "https://git.drupalcode.org/project/migrate_upgrade.git",
             "reference": "8.x-3.0-rc5"
         },
         "dist": {
             "reference": "8.x-3.0-rc5"
         },
         "dist": {
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/pathauto",
+            "url": "https://git.drupalcode.org/project/pathauto.git",
             "reference": "8.x-1.3"
         },
         "dist": {
             "reference": "8.x-1.3"
         },
         "dist": {
         "version_normalized": "1.0.0.0-alpha1",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-alpha1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/pathologic",
+            "url": "https://git.drupalcode.org/project/pathologic.git",
             "reference": "8.x-1.0-alpha1"
         },
         "dist": {
             "reference": "8.x-1.0-alpha1"
         },
         "dist": {
         "version_normalized": "1.61.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.61.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/permissions_by_term",
+            "url": "https://git.drupalcode.org/project/permissions_by_term.git",
             "reference": "8.x-1.61"
         },
         "dist": {
             "reference": "8.x-1.61"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/php",
+            "url": "https://git.drupalcode.org/project/php.git",
             "reference": "e5c1c4047f5f1522e5d630bca93d50c61ef6a2c0"
         },
         "require": {
             "reference": "e5c1c4047f5f1522e5d630bca93d50c61ef6a2c0"
         },
         "require": {
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/redirect",
+            "url": "https://git.drupalcode.org/project/redirect.git",
             "reference": "8.x-1.3"
         },
         "dist": {
             "reference": "8.x-1.3"
         },
         "dist": {
             "source": "http://cgit.drupalcode.org/redirect"
         }
     },
             "source": "http://cgit.drupalcode.org/redirect"
         }
     },
-    {
-        "name": "drupal/security_review",
-        "version": "dev-1.x",
-        "version_normalized": "dev-1.x",
-        "source": {
-            "type": "git",
-            "url": "https://git.drupal.org/project/security_review",
-            "reference": "9b8a34a21cac85913845df4eebb9a05c69de82d8"
-        },
-        "require": {
-            "drupal/core": "~8.0"
-        },
-        "type": "drupal-module",
-        "extra": {
-            "branch-alias": {
-                "dev-1.x": "1.x-dev"
-            },
-            "drupal": {
-                "version": "8.x-1.x-dev",
-                "datestamp": "1532558881",
-                "security-coverage": {
-                    "status": "not-covered",
-                    "message": "Dev releases are not covered by Drupal security advisories."
-                }
-            },
-            "patches_applied": []
-        },
-        "installation-source": "source",
-        "notification-url": "https://packages.drupal.org/8/downloads",
-        "license": [
-            "GPL-2.0-or-later"
-        ],
-        "authors": [
-            {
-                "name": "banviktor",
-                "homepage": "https://www.drupal.org/user/3176333"
-            },
-            {
-                "name": "coltrane",
-                "homepage": "https://www.drupal.org/user/91990"
-            },
-            {
-                "name": "dsnopek",
-                "homepage": "https://www.drupal.org/user/266527"
-            },
-            {
-                "name": "greggles",
-                "homepage": "https://www.drupal.org/user/36762"
-            }
-        ],
-        "description": "Site security and configuration review module.",
-        "homepage": "https://www.drupal.org/project/security_review",
-        "support": {
-            "source": "http://cgit.drupalcode.org/security_review"
-        }
-    },
     {
         "name": "drupal/simple_sitemap",
         "version": "2.12.0",
         "version_normalized": "2.12.0.0",
         "source": {
             "type": "git",
     {
         "name": "drupal/simple_sitemap",
         "version": "2.12.0",
         "version_normalized": "2.12.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/simple_sitemap",
+            "url": "https://git.drupalcode.org/project/simple_sitemap.git",
             "reference": "8.x-2.12"
         },
         "dist": {
             "reference": "8.x-2.12"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/slick",
+            "url": "https://git.drupalcode.org/project/slick.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "2.0.0.0-alpha2",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0-alpha2",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/slick_media",
+            "url": "https://git.drupalcode.org/project/slick_media.git",
             "reference": "8.x-2.0-alpha2"
         },
         "dist": {
             "reference": "8.x-2.0-alpha2"
         },
         "dist": {
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/superfish",
+            "url": "https://git.drupalcode.org/project/superfish.git",
             "reference": "8.x-1.2"
         },
         "dist": {
             "reference": "8.x-1.2"
         },
         "dist": {
         "version_normalized": "1.1.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.1.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/toc_formatter",
+            "url": "https://git.drupalcode.org/project/toc_formatter.git",
             "reference": "8.x-1.1"
         },
         "dist": {
             "reference": "8.x-1.1"
         },
         "dist": {
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/tocify",
+            "url": "https://git.drupalcode.org/project/tocify.git",
             "reference": "8.x-1.2"
         },
         "dist": {
             "reference": "8.x-1.2"
         },
         "dist": {
         "version_normalized": "1.5.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.5.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/token",
+            "url": "https://git.drupalcode.org/project/token.git",
             "reference": "8.x-1.5"
         },
         "dist": {
             "reference": "8.x-1.5"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/twig_xdebug",
+            "url": "https://git.drupalcode.org/project/twig_xdebug.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "1.0.0.0-alpha1",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0-alpha1",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/typogrify",
+            "url": "https://git.drupalcode.org/project/typogrify.git",
             "reference": "8.x-1.0-alpha1"
         },
         "dist": {
             "reference": "8.x-1.0-alpha1"
         },
         "dist": {
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/video",
+            "url": "https://git.drupalcode.org/project/video.git",
             "reference": "8.x-1.2"
         },
         "dist": {
             "reference": "8.x-1.2"
         },
         "dist": {
         "version_normalized": "2.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "2.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/video_embed_field",
+            "url": "https://git.drupalcode.org/project/video_embed_field.git",
             "reference": "8.x-2.0"
         },
         "dist": {
             "reference": "8.x-2.0"
         },
         "dist": {
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.0.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/videojs",
+            "url": "https://git.drupalcode.org/project/videojs.git",
             "reference": "8.x-1.0"
         },
         "dist": {
             "reference": "8.x-1.0"
         },
         "dist": {
         "version_normalized": "3.1.0.0",
         "source": {
             "type": "git",
         "version_normalized": "3.1.0.0",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/views_bootstrap",
+            "url": "https://git.drupalcode.org/project/views_bootstrap.git",
             "reference": "8.x-3.1"
         },
         "dist": {
             "reference": "8.x-3.1"
         },
         "dist": {
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
         "version_normalized": "dev-1.x",
         "source": {
             "type": "git",
-            "url": "https://git.drupal.org/project/views_responsive_grid",
+            "url": "https://git.drupalcode.org/project/views_responsive_grid.git",
             "reference": "b8478ccf4cb6dc6837a0c1170a848e418499a357"
         },
         "require": {
             "reference": "b8478ccf4cb6dc6837a0c1170a848e418499a357"
         },
         "require": {
         "description": "Drush config-extra contains additional configuration Drush commands, notably config-merge.",
         "keywords": [
             "Drush"
         "description": "Drush config-extra contains additional configuration Drush commands, notably config-merge.",
         "keywords": [
             "Drush"
-        ]
+        ],
+        "abandoned": true
     },
     {
         "name": "drush/drush",
     },
     {
         "name": "drush/drush",
         "version_normalized": "0.9.1.0",
         "source": {
             "type": "git",
         "version_normalized": "0.9.1.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/njh/easyrdf.git",
+            "url": "https://github.com/easyrdf/easyrdf.git",
             "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566"
         },
         "dist": {
             "type": "zip",
             "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/njh/easyrdf/zipball/acd09dfe0555fbcfa254291e433c45fdd4652566",
+            "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/acd09dfe0555fbcfa254291e433c45fdd4652566",
             "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566",
             "shasum": ""
         },
             "reference": "acd09dfe0555fbcfa254291e433c45fdd4652566",
             "shasum": ""
         },
         "version_normalized": "9999999-dev",
         "source": {
             "type": "git",
         "version_normalized": "9999999-dev",
         "source": {
             "type": "git",
-            "url": "https://github.com/grom358/pharborist.git",
+            "url": "git@github.com:grom358/pharborist.git",
             "reference": "0db9e51299a80e95b06857ed1809f59bbbab1af6"
         },
         "dist": {
             "reference": "0db9e51299a80e95b06857ed1809f59bbbab1af6"
         },
         "dist": {
                 "name": "Jakub Onderka",
                 "email": "jakub.onderka@gmail.com"
             }
                 "name": "Jakub Onderka",
                 "email": "jakub.onderka@gmail.com"
             }
-        ]
+        ],
+        "abandoned": "php-parallel-lint/php-console-color"
     },
     {
         "name": "jakub-onderka/php-console-highlighter",
     },
     {
         "name": "jakub-onderka/php-console-highlighter",
                 "homepage": "http://www.acci.cz/"
             }
         ],
                 "homepage": "http://www.acci.cz/"
             }
         ],
-        "description": "Highlight PHP code in terminal"
+        "description": "Highlight PHP code in terminal",
+        "abandoned": "php-parallel-lint/php-console-highlighter"
     },
     {
         "name": "jcalderonzumba/gastonjs",
     },
     {
         "name": "jcalderonzumba/gastonjs",
         "version_normalized": "1.6.5.0",
         "source": {
             "type": "git",
         "version_normalized": "1.6.5.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/mikey179/vfsStream.git",
+            "url": "https://github.com/bovigo/vfsStream.git",
             "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
         },
         "dist": {
             "type": "zip",
             "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
+            "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
             "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
             "shasum": ""
         },
             "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
             "shasum": ""
         },
         "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
         "keywords": [
             "tokenizer"
         "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
         "keywords": [
             "tokenizer"
-        ]
+        ],
+        "abandoned": true
     },
     {
         "name": "phpunit/phpunit",
     },
     {
         "name": "phpunit/phpunit",
         "keywords": [
             "mock",
             "xunit"
         "keywords": [
             "mock",
             "xunit"
-        ]
+        ],
+        "abandoned": true
     },
     {
         "name": "psr/container",
     },
     {
         "name": "psr/container",
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
         "version_normalized": "1.3.0.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/webmozart/assert.git",
+            "url": "https://github.com/webmozarts/assert.git",
             "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
         },
         "dist": {
             "type": "zip",
             "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
+            "url": "https://api.github.com/repos/webmozarts/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
             "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
             "shasum": ""
         },
             "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
             "shasum": ""
         },
             "http",
             "psr",
             "psr-7"
             "http",
             "psr",
             "psr-7"
-        ]
+        ],
+        "abandoned": "laminas/laminas-diactoros"
     },
     {
         "name": "zendframework/zend-escaper",
     },
     {
         "name": "zendframework/zend-escaper",
             "ZendFramework",
             "escaper",
             "zf"
             "ZendFramework",
             "escaper",
             "zf"
-        ]
+        ],
+        "abandoned": "laminas/laminas-escaper"
     },
     {
         "name": "zendframework/zend-feed",
     },
     {
         "name": "zendframework/zend-feed",
             "ZendFramework",
             "feed",
             "zf"
             "ZendFramework",
             "feed",
             "zf"
-        ]
+        ],
+        "abandoned": "laminas/laminas-feed"
     },
     {
         "name": "zendframework/zend-stdlib",
     },
     {
         "name": "zendframework/zend-stdlib",
             "ZendFramework",
             "stdlib",
             "zf"
             "ZendFramework",
             "stdlib",
             "zf"
-        ]
+        ],
+        "abandoned": "laminas/laminas-stdlib"
     }
 ]
     }
 ]
index 6a7c5320170d51c5fea78b535ee7e7d9fdda7307..692e36a4a998211052d610c93d84406a55d37044 100755 (executable)
@@ -1,7 +1,7 @@
 <?php
 
 /*
 <?php
 
 /*
-htmLawed 1.2.2, 25 May 2017
+htmLawed 1.2.6, 4 September 2021
 Copyright Santosh Patnaik
 Dual licensed with LGPL 3 and GPL 2+
 A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed
 Copyright Santosh Patnaik
 Dual licensed with LGPL 3 and GPL 2+
 A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed
@@ -37,13 +37,13 @@ else{
 }
 $C['elements'] =& $e;
 // config attrs
 }
 $C['elements'] =& $e;
 // config attrs
-$x = !empty($C['deny_attribute']) ? strtolower(str_replace(array("\n", "\r", "\t", ' '), '', $C['deny_attribute'])) : '';
-$x = array_flip((isset($x[0]) && $x[0] == '*') ? str_replace('/', 'data-', explode('-', str_replace('data-', '/', $x))) : explode(',', $x. (!empty($C['safe']) ? ',on*' : '')));
+$x = !empty($C['deny_attribute']) ? strtolower(preg_replace('"\s+-"', '/', trim($C['deny_attribute']))) : '';
+$x = array_flip((isset($x[0]) && $x[0] == '*') ? explode('/', $x) : explode(',', $x. (!empty($C['safe']) ? ',on*' : '')));
 $C['deny_attribute'] = $x;
 // config URLs
 $x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet'. (empty($C['safe']) ? ', app, javascript; *: data, javascript, ' : '; *:'). 'file, http, https';
 $C['schemes'] = array();
 $C['deny_attribute'] = $x;
 // config URLs
 $x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet'. (empty($C['safe']) ? ', app, javascript; *: data, javascript, ' : '; *:'). 'file, http, https';
 $C['schemes'] = array();
-foreach(explode(';', str_replace(array(' ', "\t", "\r", "\n"), '', $x)) as $v){
+foreach(explode(';', trim(str_replace(array(' ', "\t", "\r", "\n"), '', $x), ';')) as $v){
  $x = $x2 = null; list($x, $x2) = explode(':', $v, 2);
  if($x2){$C['schemes'][$x] = array_flip(explode(',', $x2));}
 }
  $x = $x2 = null; list($x, $x2) = explode(':', $v, 2);
  if($x2){$C['schemes'][$x] = array_flip(explode(',', $x2));}
 }
@@ -308,7 +308,7 @@ $t = $t[0];
 global $C;
 if(!($v = $C[$n = $t[3] == '-' ? 'comment' : 'cdata'])){return $t;}
 if($v == 1){return '';}
 global $C;
 if(!($v = $C[$n = $t[3] == '-' ? 'comment' : 'cdata'])){return $t;}
 if($v == 1){return '';}
-if($n == 'comment'){
+if($n == 'comment' && $v < 4){
  if(substr(($t = preg_replace('`--+`', '-', substr($t, 4, -3))), -1) != ' '){$t .= ' ';}
 }
 else{$t = substr($t, 1, -1);}
  if(substr(($t = preg_replace('`--+`', '-', substr($t, 4, -3))), -1) != ' '){$t .= ' ';}
 }
 else{$t = substr($t, 1, -1);}
@@ -366,22 +366,31 @@ return "{$b}{$p}{$a}";
 function hl_regex($p){
 // check regex
 if(empty($p)){return 0;}
 function hl_regex($p){
 // check regex
 if(empty($p)){return 0;}
-if($t = ini_get('track_errors')){$o = isset($php_errormsg) ? $php_errormsg : null;}
-else{ini_set('track_errors', 1);}
-unset($php_errormsg);
+if($v = function_exists('error_clear_last') && function_exists('error_get_last')){error_clear_last();}
+else{
+ if($t = ini_get('track_errors')){$o = isset($php_errormsg) ? $php_errormsg : null;}
+ else{ini_set('track_errors', 1);}
+ unset($php_errormsg);
+}
 if(($d = ini_get('display_errors'))){ini_set('display_errors', 0);}
 preg_match($p, '');
 if(($d = ini_get('display_errors'))){ini_set('display_errors', 0);}
 preg_match($p, '');
+if($v){$r = error_get_last() == null ? 1 : 0; }
+else{
+ $r = isset($php_errormsg) ? 0 : 1;
+ if($t){$php_errormsg = isset($o) ? $o : null;}
+ else{ini_set('track_errors', 0);}
+}
 if($d){ini_set('display_errors', 1);}
 if($d){ini_set('display_errors', 1);}
-$r = isset($php_errormsg) ? 0 : 1;
-if($t){$php_errormsg = isset($o) ? $o : null;}
-else{ini_set('track_errors', 0);}
 return $r;
 }
 
 function hl_spec($t){
 // final $spec
 $s = array();
 return $r;
 }
 
 function hl_spec($t){
 // final $spec
 $s = array();
-$t = str_replace(array("\t", "\r", "\n", ' '), '', preg_replace_callback('/"(?>(`.|[^"])*)"/sm', create_function('$m', 'return substr(str_replace(array(";", "|", "~", " ", ",", "/", "(", ")", \'`"\'), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\""), $m[0]), 1, -1);'), trim($t))); 
+if(!function_exists('hl_aux1')){function hl_aux1($m){
+ return substr(str_replace(array(";", "|", "~", " ", ",", "/", "(", ")", '`"'), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", '"'), $m[0]), 1, -1);
+}}
+$t = str_replace(array("\t", "\r", "\n", ' '), '', preg_replace_callback('/"(?>(`.|[^"])*)"/sm', 'hl_aux1', trim($t))); 
 for($i = count(($t = explode(';', $t))); --$i>=0;){
  $w = $t[$i];
  if(empty($w) or ($e = strpos($w, '=')) === false or !strlen(($a =  substr($w, $e+1)))){continue;}
 for($i = count(($t = explode(';', $t))); --$i>=0;){
  $w = $t[$i];
  if(empty($w) or ($e = strpos($w, '=')) === false or !strlen(($a =  substr($w, $e+1)))){continue;}
@@ -643,11 +652,11 @@ if($e == 'font'){
  $a2 = '';
  while(preg_match('`(^|\s)(color|size)\s*=\s*(\'|")?(.+?)(\\3|\s|$)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
  $a2 = '';
  while(preg_match('`(^|\s)(color|size)\s*=\s*(\'|")?(.+?)(\\3|\s|$)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
-  $a2 .= strtolower($m[2]) == 'color' ? (' color: '. str_replace('"', '\'', trim($m[4])). ';') : (isset($fs[($m = trim($m[4]))]) ? ($a2 .= ' font-size: '. str_replace('"', '\'', $fs[$m]). ';') : '');
+  $a2 .= strtolower($m[2]) == 'color' ? (' color: '. str_replace(array('"', ';', ':'), '\'', trim($m[4])). ';') : (isset($fs[($m = trim($m[4]))]) ? (' font-size: '. $fs[$m]. ';') : '');
  }
  while(preg_match('`(^|\s)face\s*=\s*(\'|")?([^=]+?)\\2`i', $a, $m) or preg_match('`(^|\s)face\s*=(\s*)(\S+)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
  }
  while(preg_match('`(^|\s)face\s*=\s*(\'|")?([^=]+?)\\2`i', $a, $m) or preg_match('`(^|\s)face\s*=(\s*)(\S+)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
-  $a2 .= ' font-family: '. str_replace('"', '\'', trim($m[3])). ';';
+  $a2 .= ' font-family: '. str_replace(array('"', ';', ':'), '\'', trim($m[3])). ';';
  }
  $e = 'span'; return ltrim(str_replace('<', '', $a2));
 }
  }
  $e = 'span'; return ltrim(str_replace('<', '', $a2));
 }
@@ -660,7 +669,10 @@ return '';
 function hl_tidy($t, $w, $p){
 // tidy/compact HTM
 if(strpos(' pre,script,textarea', "$p,")){return $t;}
 function hl_tidy($t, $w, $p){
 // tidy/compact HTM
 if(strpos(' pre,script,textarea', "$p,")){return $t;}
-$t = preg_replace(array('`(<\w[^>]*(?<!/)>)\s+`', '`\s+`', '`(<\w[^>]*(?<!/)>) `'), array(' $1', ' ', '$1'), preg_replace_callback(array('`(<(!\[CDATA\[))(.+?)(\]\]>)`sm', '`(<(!--))(.+?)(-->)`sm', '`(<(pre|script|textarea)[^>]*?>)(.+?)(</\2>)`sm'), create_function('$m', 'return $m[1]. str_replace(array("<", ">", "\n", "\r", "\t", " "), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), $m[3]). $m[4];'), $t));
+if(!function_exists('hl_aux2')){function hl_aux2($m){
+ return $m[1]. str_replace(array("<", ">", "\n", "\r", "\t", ' '), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), $m[3]). $m[4];
+}}
+$t = preg_replace(array('`(<\w[^>]*(?<!/)>)\s+`', '`\s+`', '`(<\w[^>]*(?<!/)>) `'), array(' $1', ' ', '$1'), preg_replace_callback(array('`(<(!\[CDATA\[))(.+?)(\]\]>)`sm', '`(<(!--))(.+?)(-->)`sm', '`(<(pre|script|textarea)[^>]*?>)(.+?)(</\2>)`sm'), 'hl_aux2', $t));
 if(($w = strtolower($w)) == -1){
  return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array('<', '>', "\n", "\r", "\t", ' '), $t);
 }
 if(($w = strtolower($w)) == -1){
  return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array('<', '>', "\n", "\r", "\t", ' '), $t);
 }
@@ -713,5 +725,5 @@ return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array(
 
 function hl_version(){
 // version
 
 function hl_version(){
 // version
-return '1.2.2';
+return '1.2.6';
 }
 }
diff --git a/web/libraries/htmLawed/htmLawedTest.php b/web/libraries/htmLawed/htmLawedTest.php
new file mode 100755 (executable)
index 0000000..a03091e
--- /dev/null
@@ -0,0 +1,692 @@
+<?php
+
+/*
+htmLawedTest.php, 21 December 2020
+To test htmLawed
+Copyright Santosh Patnaik
+Dual licensed with LGPL 3 and GPL 2+
+A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed
+
+Test htmLawed; user provides text input; input and processed input are shown as highlighted code and rendered HTML; also shown are execution time and peak memory usage
+*/
+
+// config
+$_errs = 0; // display PHP errors
+$_limit = 12000; // input character limit
+$_hlimit = 2000; // input character limit for showing hexdumps
+$_hilite = 1; // 0 turns off slow Javascript-based code-highlighting, e.g., if $_limit is high
+$_w3c_validate = 1; // 1 to show buttons to send input/output to w3c validator
+$_sid = 'sid'; // session name; alphanum.
+$_slife = 30; // session life in min.
+
+// errors
+error_reporting(E_ALL | (defined('E_STRICT') ? E_STRICT : 0));
+ini_set('display_errors', $_errs);
+
+// session
+session_name($_sid);
+session_cache_limiter('private');
+session_cache_expire($_slife);
+ini_set('session.gc_maxlifetime', $_slife * 60);
+ini_set('session.use_only_cookies', 1);
+ini_set('session.cookie_lifetime', 0);
+session_start();
+if(!isset($_SESSION['token'])){
+ $_SESSION['token'] = md5(uniqid(rand(), 1));
+}
+
+// slashes
+if(!function_exists('get_magic_quotes_gpc')){
+  function get_magic_quotes_gpc(){
+    return false;
+  }
+}
+if(!function_exists('get_magic_quotes_runtime')){
+  function get_magic_quotes_runtime(){
+    return false;
+  }
+}
+if(!function_exists('set_magic_quotes_runtime')){
+  function set_magic_quotes_runtime($new_setting){
+    return true;
+  }
+}
+if(get_magic_quotes_gpc()){
+ foreach($_POST as $k => $v){
+  $_POST[$k] = stripslashes($v);
+ }
+ ini_set('magic_quotes_gpc', 0);
+}
+if(get_magic_quotes_runtime()){
+ set_magic_quotes_runtime(0);
+}
+
+$_POST['enc'] = (isset($_POST['enc']) and preg_match('`^[-\w]+$`', $_POST['enc'])) ? $_POST['enc'] : 'utf-8';
+
+// token for anti-CSRF
+if(count($_POST)){
+ if((empty($_GET['pre']) and ((!empty($_POST['token']) and !empty($_SESSION['token']) and $_POST['token'] != $_SESSION['token']) or empty($_POST[$_sid]) or $_POST[$_sid] != session_id() or empty($_COOKIE[$_sid]) or $_COOKIE[$_sid] != session_id())) or ($_POST[$_sid] != session_id())){
+  $_POST = array('enc'=>'utf-8');
+ }
+}
+if(empty($_GET['pre'])){
+ $_SESSION['token'] = md5(uniqid(rand(), 1));
+ $token = $_SESSION['token'];
+ session_regenerate_id(1);
+}
+
+// compress
+if(function_exists('gzencode') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && preg_match('`gzip|deflate`i', $_SERVER['HTTP_ACCEPT_ENCODING']) && !ini_get('zlib.output_compression')){
+ ob_start('ob_gzhandler');
+}
+
+// HTM for unprocessed
+if(isset($_POST['inputH'])){
+ echo '<html><head><title>htmLawed test: HTML view of unprocessed input</title></head><body style="margin:0; padding: 0;"><p style="background-color: black; color: white; padding: 2px;">&nbsp; Rendering of raw/unprocessed input without an HTML doctype or charset declaration &nbsp; &nbsp; <small><a style="color: white; text-decoration: none;" href="1" onclick="javascript:window.close(this); return false;">close window</a> | <a style="color: white; text-decoration: none;" href="htmLawedTest.php" onclick="javascript: window.open(\'htmLawedTest.php\', \'hlmain\'); window.close(this); return false;">htmLawed test page</a></small></p><div>', $_POST['inputH'], '</div></body></html>';
+ exit;
+}
+
+// HTM for processed
+if(isset($_POST['outputH'])){
+ echo '<html><head><title>htmLawed test: HTML view of unprocessed input</title></head><body style="margin:0; padding: 0;"><p style="background-color: black; color: white; padding: 2px;">&nbsp; Rendering of filtered/processed input without an HTML doctype or charset declaration &nbsp; &nbsp; <small><a style="color: white; text-decoration: none;" href="1" onclick="javascript:window.close(this); return false;">close window</a> | <a style="color: white; text-decoration: none;" href="htmLawedTest.php" onclick="javascript: window.open(\'htmLawedTest.php\', \'hlmain\'); window.close(this); return false;">htmLawed test page</a></small></p><div>', $_POST['outputH'], '</div></body></html>';
+ exit;
+}
+
+// main
+$_POST['text'] = isset($_POST['text']) ? $_POST['text'] : 'text to process; < '. $_limit. ' characters'. ($_hlimit ? ' (for binary hexdump view, < '. $_hlimit. ')' : '');
+$do = (!empty($_POST[$_sid]) && isset($_POST['text'][0]) && !isset($_POST['text'][$_limit])) ? 1 : 0;
+$limit_exceeded = isset($_POST['text'][$_limit]) ? 1 : 0;
+$pre_mem = memory_get_usage();
+$validation = (!empty($_POST[$_sid]) and isset($_POST['w3c_validate'][0])) ? 1 : 0;
+include './htmLawed.php';
+
+function format($t){
+ $t = "\n". str_replace(array("\t", "\r\n", "\r", '&', '<', '>', "\n"), array('    ', "\n", "\n", '&amp;', '&lt;', '&gt;', "<span class=\"newline\">&#172;</span><br />\n"), $t);
+ return str_replace(array('<br />', "\n ", '  '), array("\n<br />\n", "\n&nbsp;", ' &nbsp;'), $t);
+}
+
+function hexdump($d){
+// Mainly by Aidan Lister <aidan@php.net>, Peter Waller <iridum@php.net>
+ $hexi = '';
+ $ascii = '';
+ ob_start();
+ echo '<pre>';
+ $offset = 0;
+ $len = strlen($d);
+ for($i=$j=0; $i<$len; $i++)
+ {
+  // Convert to hexidecimal
+  $hexi .= sprintf("%02X ", ord($d[$i]));
+  // Replace non-viewable bytes with '.'
+  if(ord($d[$i]) >= 32){
+   $ascii .= htmlspecialchars($d[$i]);
+  }else{
+   $ascii .= '.';
+  } 
+  // Add extra column spacing
+  if($j == 7){
+   $hexi .= ' ';
+   $ascii .= '  ';
+  }
+  // Add row
+  if(++$j == 16 || $i == $len-1){
+   // Join the hexi / ascii output
+   echo sprintf("%04X   %-49s   %s", $offset, $hexi, $ascii);   
+   // Reset vars
+   $hexi = $ascii = '';
+   $offset += 16;
+   $j = 0;  
+   // Add newline   
+   if ($i !== $len-1){
+    echo "\n";
+   }
+  }
+ }
+ echo '</pre>';
+ $o = ob_get_contents();
+ ob_end_clean();
+ return $o;
+}
+?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en" xml:lang="en">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<meta name="description" content="htmLawed <?php echo hl_version();?> test page" />
+<style type="text/css"><!--/*--><![CDATA[/*><!--*/
+a, a.resizer{text-decoration:none;}
+a:hover, a.resizer:hover{color:red;}
+a.resizer{color:green; float:right;}
+body{background-color:#efefef;}
+body, button, div, html, input, p{font-size:13px; font-family:'Lucida grande', Verdana, Arial, Helvetica, sans-serif;}
+button, input{font-size: 85%;}
+div.help{border-top: 1px dotted gray; margin-top: 15px; padding-top: 15px; color:#999999;}
+#inputC, #inputD, #inputF, #inputR, #outputD, #outputF, #outputR, #settingF, #diff{display:block;}
+#inputC, #settingF{background-color:white; border:1px gray solid; padding:3px;}
+#inputC li{margin: 0; padding: 0;}
+#inputC ul{margin: 0; padding: 0; margin-left: 14px;}
+#inputC input{margin: 0; margin-left: 2px; margin-right: 2px; padding: 1px; vertical-align: middle;}
+#inputD{overflow:auto; background-color:#ffff99; border:1px #cc9966 solid; padding:3px;}
+#inputR{overflow:auto; background-color:#ffffcc; border:1px #ffcc99 solid; padding:3px;}
+#inputC, #settingF, #inputD, #inputR, #outputD, #outputR, #diff, textarea{font-size:100%; font-family:'Bitstream vera sans mono', 'courier new', 'courier', monospace;}
+#outputD{overflow:auto; background-color: #99ffcc; border:1px #66cc99 solid; padding:3px;}
+#diff{overflow:auto; background-color: white; border:1px #dcdcdc solid; padding:3px;}
+#outputR{overflow:auto; background-color: #ccffcc; border:1px #99cc99 solid; padding:3px;} 
+span.cmtcdata{color: orange;}
+span.ctag{color:red;}
+span.ent{border-bottom:1px dotted #999999;}
+span.etag{color:purple;}
+span.help{color:#999999;}
+span.newline{color:#dcdcdc;}
+span.notice{color:green;}
+span.otag{color:blue;}
+#topmost{margin:auto; width:98%;}
+/*]]>*/--></style>
+<script type="text/javascript"><!--//--><![CDATA[//><!-- 
+window.name = 'hlmain';
+function hl(i){
+ <?php if(!$_hilite){echo 'return;'; }?>
+ var e = document.getElementById(i);
+ if(!e){return;}
+ run(e, '</[a-z1-6]+>', 'ctag');
+ run(e, '<[a-z]+(?:[^>]*)/>', 'etag');
+ run(e, '<[a-z1-6]+(?:[^>]*)>', 'otag');
+ run(e, '&[#a-z0-9]+;', 'ent');
+ run(e, '<!(?:(?:--(?:.|\n)*?--)|(?:\\[CDATA\\[(?:.|\n)*?\\]\\]))>', 'cmtcdata');
+}
+function sndProc(){
+ var f = document.getElementById('testform');
+ if(!f){return;}
+ var e = document.createElement('input');
+ e.type = 'hidden';
+ e.name = '<?php echo htmlspecialchars($_sid); ?>';
+ e.id = '<?php echo htmlspecialchars($_sid); ?>';
+ e.value = readCookie('<?php echo htmlspecialchars($_sid); ?>');
+ f.appendChild(e);
+ f.submit();
+}
+function readCookie(n){
+ var ne = n + '=';
+ var ca = document.cookie.split(';');
+ for(var i=0;i < ca.length;i++){
+  var c = ca[i];
+  while(c.charAt(0)==' '){
+   c = c.substring(1,c.length);
+  }
+  if(c.indexOf(ne) == 0){
+   return c.substring(ne.length,c.length);
+  }
+ }
+ return null;
+}
+function run(e, q, c){
+ var q = new RegExp(q);
+ if(e.firstChild == null){
+  var m = q.exec(e.data);
+  if(m){
+   var v = m[0];
+   var k2 = e.splitText(m.index);
+   var k3 = k2.splitText(v.length);
+   var s = e.ownerDocument.createElement('span');
+   e.parentNode.replaceChild(s, k2);
+   s.className = c; s.appendChild(k2);
+  }
+ }
+ for(var k = e.firstChild; k != null; k = k.nextSibling){
+  if(k.nodeType == 3){     
+   var m = q.exec(k.data);
+   if(m){
+    var v = m[0];
+    var k2 = k.splitText(m.index);
+    var k3 = k2.splitText(v.length);
+    var s = k.ownerDocument.createElement('span');
+    k.parentNode.replaceChild(s, k2);
+    s.className = c; s.appendChild(k2);
+   }
+  }
+  else if(c == 'ent' && k.nodeType == 1){
+   var d = k.firstChild;
+   if(d){
+    var m = q.exec(d.data);
+    if(m){
+     var v = m[0];
+     var d2 = d.splitText(m.index);
+     var d3 = d2.splitText(v.length);
+     var s = d.ownerDocument.createElement('span');
+     d.parentNode.replaceChild(s, d2);
+     s.className = c; s.appendChild(d2);
+    }
+   }
+  }
+ }
+}
+function toggle(i){  
+ var e = document.getElementById(i);  
+ if(!e){return;}
+ if(e.style){
+  var a = e.style.display;   
+  if(a == 'block'){e.style.display = 'none'; return;}
+  if(a == 'none'){e.style.display = 'block';}
+  else{e.style.display = 'none';}
+  return;   
+ }
+ var a = e.visibility;
+ if(a == 'hidden'){e.visibility = 'show'; return;}
+ if(a == 'show'){e.visibility = 'hidden';}
+}
+function sndProc2(){
+ var i = document.getElementById('text2');
+ if(!i){return;}
+ i = i.value;
+ var w = window.open('htmLawedTest.php?pre=1', 'hlposthtm');
+ var f = document.createElement('form');
+ f.enctype = 'application/x-www-form-urlencoded';
+ f.method = 'post';
+ f.acceptCharset = '<?php echo htmlspecialchars($_POST['enc']); ?>';
+ if(f.style){f.style.display = 'none';}
+ else{f.visibility = 'hidden';}
+ f.innerHTML = '<p style="display:none;"><input style="display:none;" type="hidden" name="token" id="token" value="<?php echo $token; ?>" /><input style="display:none;" type="hidden" name="<?php echo htmlspecialchars($_sid); ?>" id="<?php echo htmlspecialchars($_sid); ?>" value="' + readCookie('<?php echo htmlspecialchars($_sid); ?>') + '" /></p>';
+ f.action = 'htmLawedTest.php?pre=1';
+ f.target = 'hlposthtm';
+ f.method = 'post';
+ var t = document.createElement('textarea');
+ t.name = 'outputH';
+ t.value = i;
+ f.appendChild(t);
+ var b = document.getElementsByTagName('body')[0];
+ b.appendChild(f);
+ f.submit();
+ w.focus;
+}
+function sndUnproc(){
+ var i = document.getElementById('text');
+ if(!i){return;}
+ i = i.value;
+ var w = window.open('htmLawedTest.php?pre=1', 'hlprehtm');
+ var f = document.createElement('form');
+ f.enctype = 'application/x-www-form-urlencoded';
+ f.method = 'post';
+ f.acceptCharset = '<?php echo htmlspecialchars($_POST['enc']); ?>';
+ if(f.style){f.style.display = 'none';}
+ else{f.visibility = 'hidden';}
+ f.innerHTML = '<p style="display:none;"><input style="display:none;" type="hidden" name="token" id="token" value="<?php echo $token; ?>" /><input style="display:none;" type="hidden" name="<?php echo htmlspecialchars($_sid); ?>" id="<?php echo htmlspecialchars($_sid); ?>" value="' + readCookie('<?php echo htmlspecialchars($_sid); ?>') + '" /></p>';
+ f.action = 'htmLawedTest.php?pre=1';
+ f.target = 'hlprehtm';
+ f.method = 'post';
+ var t = document.createElement('textarea');
+ t.name = 'inputH';
+ t.value = i;
+ f.appendChild(t);
+ var b = document.getElementsByTagName('body')[0];
+ b.appendChild(f);
+ f.submit();
+ w.focus;
+}
+function sndValidn(id, type){
+ var i = document.getElementById(id);
+ if(!i){return;}
+ i = i.value;
+ var w = window.open('http://validator.w3.org/check', 'validate'+id+type);
+ var f = document.createElement('form');
+ f.enctype = 'application/x-www-form-urlencoded';
+ f.method = 'post';
+ f.acceptCharset = '<?php echo htmlspecialchars($_POST['enc']); ?>';
+ if(f.style){f.style.display = 'none';}
+ else{f.visibility = 'hidden';}
+ f.innerHTML = '<p style="display:none;"><input style="display:none;" type="hidden" name="prefill" id="prefill" value="1" /><input style="display:none;" type="hidden" name="prefill_doctype" id="prefill_doctype" value="'+ type+ '" /><input style="display:none;" type="hidden" name="group" id="group" value="1" /><input type="hidden" name="ss" id="ss" value="1" /></p>';
+ f.action = 'http://validator.w3.org/check';
+ f.target = 'validate'+id+type;
+ var t = document.createElement('textarea');
+ t.name = 'fragment';
+ t.value = i;
+ f.appendChild(t);
+ var b = document.getElementsByTagName('body')[0];
+ b.appendChild(f);
+ f.submit();
+ w.focus;
+}
+tRs = {
+ formEl: null,
+ resizeClass: 'textarea',
+ adEv: function(t,ev,fn){
+  if(typeof document.addEventListener != 'undefined'){
+   t.addEventListener(ev,fn,false);
+  }else{
+   t.attachEvent('on' + ev, fn);
+  }
+ },
+ rmEv: function(t,ev,fn){
+  if(typeof document.removeEventListener != 'undefined'){
+   t.removeEventListener(ev,fn,false);
+  }else
+  {
+   t.detachEvent('on' + ev, fn);
+  }
+ },
+ adBtn: function(){
+  var textareas = document.getElementsByTagName('textarea');
+  for(var i = 0; i < textareas.length; i++){   
+   var txtclass=textareas[i].className;
+   if(txtclass.substring(0,tRs.resizeClass.length)==tRs.resizeClass ||
+   txtclass.substring(txtclass.length -tRs.resizeClass.length)==tRs.resizeClass){
+    var a = document.createElement('a');
+    a.appendChild(document.createTextNode("\u2195"));
+    a.style.cursor = 'n-resize';
+    a.className= 'resizer';
+    a.title = 'click-drag to resize textarea'
+    tRs.adEv(a, 'mousedown', tRs.initResize);
+    textareas[i].parentNode.appendChild(a);
+   }   
+  }
+ },
+ initResize: function(event){
+  if(typeof event == 'undefined'){
+   event = window.event;
+  }
+  if(event.srcElement){
+   var target = event.srcElement.previousSibling;
+  }else{
+   var target = event.target.previousSibling;
+  }
+  if(target.nodeName.toLowerCase() == 'textarea' || (target.nodeName.toLowerCase() == 'input' && target.type == 'text')){
+   tRs.formEl = target;
+   tRs.formEl.startHeight = tRs.formEl.clientHeight;
+   tRs.formEl.startY = event.clientY;
+   tRs.adEv(document, 'mousemove', tRs.resize);
+   tRs.adEv(document, 'mouseup', tRs.stopResize);
+   tRs.formEl.parentNode.style.cursor = 'n-resize';
+   tRs.formEl.style.cursor = 'n-resize';
+   try{
+    event.preventDefault();
+   }catch(e){
+   }
+  }
+ },
+ resize: function(event){
+  if(typeof event == 'undefined'){
+   event = window.event;
+  }
+       if(tRs.formEl.nodeName.toLowerCase() == 'textarea'){
+   tRs.formEl.style.height = event.clientY - tRs.formEl.startY + tRs.formEl.startHeight + 'px';
+  }
+ },
+ stopResize: function(event){
+  tRs.rmEv(document, 'mousedown', tRs.initResize);
+  tRs.rmEv(document, 'mousemove', tRs.resize);
+  tRs.formEl.style.cursor = 'text';
+  tRs.formEl.parentNode.style.cursor = 'auto';
+  return false;
+ }
+};
+tRs.adEv(window, 'load', tRs.adBtn);
+// Diff Match and Patch javascript code by Neil Fraser; Apache license 2.0; http://code.google.com/p/google-diff-match-patch/
+(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32}
+diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b),c=a.substring(0,f),a=a.substring(f),b=b.substring(f),f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f),a=a.substring(0,a.length-f),b=b.substring(0,b.length-f),a=this.diff_compute_(a,
+b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a};
+diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);if(-1!=g)return c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c;if(1==f.length)return[[-1,a],[1,b]];return(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100<a.length&&100<b.length?this.diff_lineMode_(a,
+b,d):this.diff_bisect_(a,b,d)};
+diff_match_patch.prototype.diff_lineMode_=function(a,b,c){var d=this.diff_linesToChars_(a,b),a=d.chars1,b=d.chars2,d=d.lineArray,a=this.diff_main(a,b,!1,c);this.diff_charsToLines_(a,d);this.diff_cleanupSemantic(a);a.push([0,""]);for(var e=d=b=0,f="",g="";b<a.length;){switch(a[b][0]){case 1:e++;g+=a[b][1];break;case -1:d++;f+=a[b][1];break;case 0:if(1<=d&&1<=e){a.splice(b-d-e,d+e);b=b-d-e;d=this.diff_main(f,g,!1,c);for(e=d.length-1;0<=e;e--)a.splice(b,0,d[e]);b+=d.length}d=e=0;g=f=""}b++}a.pop();return a};
+diff_match_patch.prototype.diff_bisect_=function(a,b,c){for(var d=a.length,e=b.length,f=Math.ceil((d+e)/2),g=f,h=2*f,j=Array(h),i=Array(h),k=0;k<h;k++)j[k]=-1,i[k]=-1;j[g+1]=0;i[g+1]=0;for(var k=d-e,p=0!=k%2,q=0,s=0,o=0,v=0,u=0;u<f&&!((new Date).getTime()>c);u++){for(var n=-u+q;n<=u-s;n+=2){var l=g+n,m;m=n==-u||n!=u&&j[l-1]<j[l+1]?j[l+1]:j[l-1]+1;for(var r=m-n;m<d&&r<e&&a.charAt(m)==b.charAt(r);)m++,r++;j[l]=m;if(m>d)s+=2;else if(r>e)q+=2;else if(p&&(l=g+k-n,0<=l&&l<h&&-1!=i[l])){var t=d-i[l];if(m>=
+t)return this.diff_bisectSplit_(a,b,m,r,c)}}for(n=-u+o;n<=u-v;n+=2){l=g+n;t=n==-u||n!=u&&i[l-1]<i[l+1]?i[l+1]:i[l-1]+1;for(m=t-n;t<d&&m<e&&a.charAt(d-t-1)==b.charAt(e-m-1);)t++,m++;i[l]=t;if(t>d)v+=2;else if(m>e)o+=2;else if(!p&&(l=g+k-n,0<=l&&l<h&&-1!=j[l]&&(m=j[l],r=g+m-l,t=d-t,m>=t)))return this.diff_bisectSplit_(a,b,m,r,c)}}return[[-1,a],[1,b]]};
+diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d),a=a.substring(c),b=b.substring(d),f=this.diff_main(f,g,!1,e),e=this.diff_main(a,b,!1,e);return f.concat(e)};
+diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;f<a.length-1;){f=a.indexOf("\n",c);-1==f&&(f=a.length-1);var q=a.substring(c,f+1),c=f+1;(e.hasOwnProperty?e.hasOwnProperty(q):void 0!==e[q])?b+=String.fromCharCode(e[q]):(b+=String.fromCharCode(g),e[q]=g,d[g++]=q)}return b}var d=[],e={};d[0]="";var f=c(a),g=c(b);return{chars1:f,chars2:g,lineArray:d}};
+diff_match_patch.prototype.diff_charsToLines_=function(a,b){for(var c=0;c<a.length;c++){for(var d=a[c][1],e=[],f=0;f<d.length;f++)e[f]=b[d.charCodeAt(f)];a[c][1]=e.join("")}};diff_match_patch.prototype.diff_commonPrefix=function(a,b){if(!a||!b||a.charAt(0)!=b.charAt(0))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(f,e)==b.substring(f,e)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
+diff_match_patch.prototype.diff_commonSuffix=function(a,b){if(!a||!b||a.charAt(a.length-1)!=b.charAt(b.length-1))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(a.length-e,a.length-f)==b.substring(b.length-e,b.length-f)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
+diff_match_patch.prototype.diff_commonOverlap_=function(a,b){var c=a.length,d=b.length;if(0==c||0==d)return 0;c>d?a=a.substring(c-d):c<d&&(b=b.substring(0,c));c=Math.min(c,d);if(a==b)return c;for(var d=0,e=1;;){var f=a.substring(c-e),f=b.indexOf(f);if(-1==f)return d;e+=f;if(0==f||a.substring(c-e)==b.substring(0,e))d=e,e++}};
+diff_match_patch.prototype.diff_halfMatch_=function(a,b){function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1,g="",h,j,n,l;-1!=(e=b.indexOf(d,e+1));){var m=f.diff_commonPrefix(a.substring(c),b.substring(e)),r=f.diff_commonSuffix(a.substring(0,c),b.substring(0,e));g.length<r+m&&(g=b.substring(e-r,e)+b.substring(e,e+m),h=a.substring(0,c-r),j=a.substring(c+m),n=b.substring(0,e-r),l=b.substring(e+m))}return 2*g.length>=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;
+var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.length<d.length)return null;var f=this,g=c(d,e,Math.ceil(d.length/4)),d=c(d,e,Math.ceil(d.length/2)),h;if(!g&&!d)return null;h=d?g?g[4].length>d[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]};
+diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f<a.length;)0==a[f][0]?(c[d++]=f,g=j,h=i,i=j=0,e=a[f][1]):(1==a[f][0]?j+=a[f][1].length:i+=a[f][1].length,e&&e.length<=Math.max(g,h)&&e.length<=Math.max(j,i)&&(a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,d--,f=0<d?c[d-1]:-1,i=j=h=g=0,e=null,b=!0)),f++;b&&this.diff_cleanupMerge(a);this.diff_cleanupSemanticLossless(a);for(f=1;f<a.length;){if(-1==a[f-1][0]&&1==a[f][0]){b=a[f-1][1];c=a[f][1];
+d=this.diff_commonOverlap_(b,c);e=this.diff_commonOverlap_(c,b);if(d>=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}};
+diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);
+return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c<a.length-1;){if(0==a[c-1][0]&&0==a[c+1][0]){var d=a[c-1][1],e=a[c][1],f=a[c+1][1],g=this.diff_commonSuffix(d,e);if(g)var h=e.substring(e.length-g),d=d.substring(0,d.length-g),e=h+e.substring(0,e.length-g),f=h+f;for(var g=d,h=e,j=f,i=b(d,e)+b(e,f);e.charAt(0)===f.charAt(0);){var d=d+e.charAt(0),e=e.substring(1)+f.charAt(0),f=f.substring(1),k=b(d,e)+b(e,f);k>=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=
+h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
+diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;f<a.length;){if(0==a[f][0])a[f][1].length<this.Diff_EditCost&&(j||i)?(c[d++]=f,g=j,h=i,e=a[f][1]):(d=0,e=null),j=i=!1;else if(-1==a[f][0]?i=!0:j=!0,e&&(g&&h&&j&&i||e.length<this.Diff_EditCost/2&&3==g+h+j+i))a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,e=null,g&&h?(j=i=!0,d=0):(d--,f=0<d?c[d-1]:-1,j=i=!1),b=!0;f++}b&&this.diff_cleanupMerge(a)};
+diff_match_patch.prototype.diff_cleanupMerge=function(a){a.push([0,""]);for(var b=0,c=0,d=0,e="",f="",g;b<a.length;)switch(a[b][0]){case 1:d++;f+=a[b][1];b++;break;case -1:c++;e+=a[b][1];b++;break;case 0:1<c+d?(0!==c&&0!==d&&(g=this.diff_commonPrefix(f,e),0!==g&&(0<b-c-d&&0==a[b-c-d-1][0]?a[b-c-d-1][1]+=f.substring(0,g):(a.splice(0,0,[0,f.substring(0,g)]),b++),f=f.substring(g),e=e.substring(g)),g=this.diff_commonSuffix(f,e),0!==g&&(a[b][1]=f.substring(f.length-g)+a[b][1],f=f.substring(0,f.length-
+g),e=e.substring(0,e.length-g))),0===c?a.splice(b-d,c+d,[1,f]):0===d?a.splice(b-c,c+d,[-1,e]):a.splice(b-c-d,c+d,[-1,e],[1,f]),b=b-c-d+(c?1:0)+(d?1:0)+1):0!==b&&0==a[b-1][0]?(a[b-1][1]+=a[b][1],a.splice(b,1)):b++,c=d=0,f=e=""}""===a[a.length-1][1]&&a.pop();c=!1;for(b=1;b<a.length-1;)0==a[b-1][0]&&0==a[b+1][0]&&(a[b][1].substring(a[b][1].length-a[b-1][1].length)==a[b-1][1]?(a[b][1]=a[b-1][1]+a[b][1].substring(0,a[b][1].length-a[b-1][1].length),a[b+1][1]=a[b-1][1]+a[b+1][1],a.splice(b-1,1),c=!0):a[b][1].substring(0,
+a[b+1][1].length)==a[b+1][1]&&(a[b-1][1]+=a[b+1][1],a[b][1]=a[b][1].substring(a[b+1][1].length)+a[b+1][1],a.splice(b+1,1),c=!0)),b++;c&&this.diff_cleanupMerge(a)};diff_match_patch.prototype.diff_xIndex=function(a,b){var c=0,d=0,e=0,f=0,g;for(g=0;g<a.length;g++){1!==a[g][0]&&(c+=a[g][1].length);-1!==a[g][0]&&(d+=a[g][1].length);if(c>b)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)};
+diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=/</g,e=/>/g,f=/\n/g,g=0;g<a.length;g++){var h=a[g][0],j=a[g][1],j=j.replace(c,"&amp;").replace(d,"&lt;").replace(e,"&gt;").replace(f,"<span style=\"color: #dcdcdc;\">&not;</span><br>");switch(h){case 1:b[g]='<ins style="background:#ccffcc; text-decoration: none;">'+j+"</ins>";break;case -1:b[g]='<del style="background:#ffffcc; text-decoration: line-through; color: orange;">'+j+"</del>";break;case 0:b[g]="<span>"+j+"</span>"}}return b.join("")};
+diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;c<a.length;c++)1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_text2=function(a){for(var b=[],c=0;c<a.length;c++)-1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_levenshtein=function(a){for(var b=0,c=0,d=0,e=0;e<a.length;e++){var f=a[e][0],g=a[e][1];switch(f){case 1:c+=g.length;break;case -1:d+=g.length;break;case 0:b+=Math.max(c,d),d=c=0}}return b+=Math.max(c,d)};
+diff_match_patch.prototype.diff_toDelta=function(a){for(var b=[],c=0;c<a.length;c++)switch(a[c][0]){case 1:b[c]="+"+encodeURI(a[c][1]);break;case -1:b[c]="-"+a[c][1].length;break;case 0:b[c]="="+a[c][1].length}return b.join("\t").replace(/%20/g," ")};
+diff_match_patch.prototype.diff_fromDelta=function(a,b){for(var c=[],d=0,e=0,f=b.split(/\t/g),g=0;g<f.length;g++){var h=f[g].substring(1);switch(f[g].charAt(0)){case "+":try{c[d++]=[1,decodeURI(h)]}catch(j){throw Error("Illegal escape in diff_fromDelta: "+h);}break;case "-":case "=":var i=parseInt(h,10);if(isNaN(i)||0>i)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=i);"="==f[g].charAt(0)?c[d++]=[0,h]:c[d++]=[-1,h];break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+
+f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
+diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return!f.Match_Distance?g?1:e:e+g/f.Match_Distance}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<<b.length-1,h=-1,i,k,p=b.length+a.length,q,s=0;s<b.length;s++){i=0;for(k=p;i<k;)d(s,c+
+k)<=g?i=k:p=k,k=Math.floor((p-i)/2+i);p=k;i=Math.max(1,c-k+1);var o=Math.min(c+k,a.length)+b.length;k=Array(o+2);for(k[o+1]=(1<<s)-1;o>=i;o--){var v=e[a.charAt(o-1)];k[o]=0===s?(k[o+1]<<1|1)&v:(k[o+1]<<1|1)&v|(q[o+1]|q[o])<<1|1|q[o+1];if(k[o]&j&&(v=d(s,o-1),v<=g))if(g=v,h=o-1,h>c)i=Math.max(1,2*c-h);else break}if(d(s+1,c)>g)break;q=k}return h};
+diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c<a.length;c++)b[a.charAt(c)]=0;for(c=0;c<a.length;c++)b[a.charAt(c)]|=1<<a.length-c-1;return b};
+diff_match_patch.prototype.patch_addContext_=function(a,b){if(0!=b.length){for(var c=b.substring(a.start2,a.start2+a.length1),d=0;b.indexOf(c)!=b.lastIndexOf(c)&&c.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)d+=this.Patch_Margin,c=b.substring(a.start2-d,a.start2+a.length1+d);d+=this.Patch_Margin;(c=b.substring(a.start2-d,a.start2))&&a.diffs.unshift([0,c]);(d=b.substring(a.start2+a.length1,a.start2+a.length1+d))&&a.diffs.push([0,d]);a.start1-=c.length;a.start2-=c.length;a.length1+=
+c.length+d.length;a.length2+=c.length+d.length}};
+diff_match_patch.prototype.patch_make=function(a,b,c){var d;if("string"==typeof a&&"string"==typeof b&&"undefined"==typeof c)d=a,b=this.diff_main(d,b,!0),2<b.length&&(this.diff_cleanupSemantic(b),this.diff_cleanupEfficiency(b));else if(a&&"object"==typeof a&&"undefined"==typeof b&&"undefined"==typeof c)b=a,d=this.diff_text1(b);else if("string"==typeof a&&b&&"object"==typeof b&&"undefined"==typeof c)d=a;else if("string"==typeof a&&"string"==typeof b&&c&&"object"==typeof c)d=a,b=c;else throw Error("Unknown call format to patch_make.");
+if(0===b.length)return[];for(var c=[],a=new diff_match_patch.patch_obj,e=0,f=0,g=0,h=d,j=0;j<b.length;j++){var i=b[j][0],k=b[j][1];if(!e&&0!==i)a.start1=f,a.start2=g;switch(i){case 1:a.diffs[e++]=b[j];a.length2+=k.length;d=d.substring(0,g)+k+d.substring(g);break;case -1:a.length1+=k.length;a.diffs[e++]=b[j];d=d.substring(0,g)+d.substring(g+k.length);break;case 0:k.length<=2*this.Patch_Margin&&e&&b.length!=j+1?(a.diffs[e++]=b[j],a.length1+=k.length,a.length2+=k.length):k.length>=2*this.Patch_Margin&&
+e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new diff_match_patch.patch_obj;e.diffs=[];for(var f=0;f<d.diffs.length;f++)e.diffs[f]=d.diffs[f].slice();e.start1=d.start1;e.start2=d.start2;e.length1=d.length1;e.length2=d.length2;b[c]=e}return b};
+diff_match_patch.prototype.patch_apply=function(a,b){if(0==a.length)return[b,[]];var a=this.patch_deepCopy(a),c=this.patch_addPadding(a),b=c+b+c;this.patch_splitMax(a);for(var d=0,e=[],f=0;f<a.length;f++){var g=a[f].start2+d,h=this.diff_text1(a[f].diffs),j,i=-1;if(h.length>this.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);
+if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;i<a[f].diffs.length;i++){var p=a[f].diffs[i];0!==p[0]&&(k=this.diff_xIndex(g,h));1===p[0]?b=b.substring(0,
+j+k)+p[1]+b.substring(j+k):-1===p[0]&&(b=b.substring(0,j+k)+b.substring(j+this.diff_xIndex(g,h+p[1].length)));-1!==p[0]&&(h+=p[1].length)}}}b=b.substring(c.length,b.length-c.length);return[b,e]};
+diff_match_patch.prototype.patch_addPadding=function(a){for(var b=this.Patch_Margin,c="",d=1;d<=b;d++)c+=String.fromCharCode(d);for(d=0;d<a.length;d++)a[d].start1+=b,a[d].start2+=b;var d=a[0],e=d.diffs;if(0==e.length||0!=e[0][0])e.unshift([0,c]),d.start1-=b,d.start2-=b,d.length1+=b,d.length2+=b;else if(b>e[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,
+c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
+diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c<a.length;c++)if(!(a[c].length1<=b)){var d=a[c];a.splice(c--,1);for(var e=d.start1,f=d.start2,g="";0!==d.diffs.length;){var h=new diff_match_patch.patch_obj,j=!0;h.start1=e-g.length;h.start2=f-g.length;if(""!==g)h.length1=h.length2=g.length,h.diffs.push([0,g]);for(;0!==d.diffs.length&&h.length1<b-this.Patch_Margin;){var g=d.diffs[0][0],i=d.diffs[0][1];1===g?(h.length2+=i.length,f+=i.length,h.diffs.push(d.diffs.shift()),
+j=!1):-1===g&&1==h.diffs.length&&0==h.diffs[0][0]&&i.length>2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&
+(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b.join("")};
+diff_match_patch.prototype.patch_fromText=function(a){var b=[];if(!a)return b;for(var a=a.split("\n"),c=0,d=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;c<a.length;){var e=a[c].match(d);if(!e)throw Error("Invalid patch string: "+a[c]);var f=new diff_match_patch.patch_obj;b.push(f);f.start1=parseInt(e[1],10);""===e[2]?(f.start1--,f.length1=1):"0"==e[2]?f.length1=0:(f.start1--,f.length1=parseInt(e[2],10));f.start2=parseInt(e[3],10);""===e[4]?(f.start2--,f.length2=1):"0"==e[4]?f.length2=0:(f.start2--,f.length2=
+parseInt(e[4],10));for(c++;c<a.length;){e=a[c].charAt(0);try{var g=decodeURI(a[c].substring(1))}catch(h){throw Error("Illegal escape in patch_fromText: "+g);}if("-"==e)f.diffs.push([-1,g]);else if("+"==e)f.diffs.push([1,g]);else if(" "==e)f.diffs.push([0,g]);else if("@"==e)break;else if(""!==e)throw Error('Invalid patch mode "'+e+'" in: '+g);c++}}return b};diff_match_patch.patch_obj=function(){this.diffs=[];this.start2=this.start1=null;this.length2=this.length1=0};
+diff_match_patch.patch_obj.prototype.toString=function(){var a,b;a=0===this.length1?this.start1+",0":1==this.length1?this.start1+1:this.start1+1+","+this.length1;b=0===this.length2?this.start2+",0":1==this.length2?this.start2+1:this.start2+1+","+this.length2;a=["@@ -"+a+" +"+b+" @@\n"];var c;for(b=0;b<this.diffs.length;b++){switch(this.diffs[b][0]){case 1:c="+";break;case -1:c="-";break;case 0:c=" "}a[b+1]=c+encodeURI(this.diffs[b][1])+"\n"}return a.join("").replace(/%20/g," ")};
+this.diff_match_patch=diff_match_patch;this.DIFF_DELETE=-1;this.DIFF_INSERT=1;this.DIFF_EQUAL=0;})()
+var dmp = new diff_match_patch(); function diffLaunch(){var text1 = document.getElementById('text').value; var text2 = document.getElementById('text2').value; dmp.Diff_Timeout = 0; dmp.Diff_EditCost = 4; var d = dmp.diff_main(text1, text2); var ds = dmp.diff_prettyHtml(d); document.getElementById('diff').innerHTML = ds;
+}
+//--><!]]></script>
+<title>htmLawed (<?php echo hl_version();?>) test</title>
+</head>
+<body>
+<div id="topmost">
+
+<h5 style="float: left; display: inline; margin-top: 0; margin-bottom: 5px;"><a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php" title="htmLawed home">HTM<big><big>L</big></big>AWED</a> <?php echo hl_version();?> <a href="htmLawedTest.php" title="test home">TEST</a></h5>
+<span style="float: right;" class="help"><a href="htmLawed_README.htm"><span class="notice">htm</span></a> / <a href="htmLawed_README.txt"><span class="notice">txt</span></a> documentation</span><br style="clear:both;" />
+
+<a href="htmLawedTest.php" title="[toggle visibility] type or copy-paste" onclick="javascript:toggle('inputF'); return false;"><span class="notice">Input &raquo;</span> <span class="help" title="limit lower with multibyte characters<?php echo (($_hlimit < $_limit && $_hlimit)? '; limit is '. $_hlimit. ' for viewing binaries' : ''); ?>"><small>(max. <?php echo htmlspecialchars($_limit);?> chars)</small></span></a>
+
+<form id="testform" name="testform" action="htmLawedTest.php" method="post" accept-charset="<?php echo htmlspecialchars($_POST['enc']); ?>" style="padding:0; margin: 0; display:inline;">
+
+<div id="inputF" style="display: block;">
+
+<input type="hidden" name="token" id="token" value="<?php echo $token; ?>" />
+<div><textarea id="text" class="textarea" name="text" rows="5" cols="100" style="width: 100%;"><?php echo htmlspecialchars($_POST['text']);?></textarea></div>
+<input type="submit" id="submitF" name="submitF" value="Process" style="float:left;" title="filter using htmLawed" onclick="javascript: sndProc(); return false;" onkeypress="javascript: sndProc(); return false;" />
+
+<?php
+if($do){
+ if($validation){
+  echo '<input type="hidden" value="1" name="w3c_validate" id="w3c_validate" />';
+ }
+?>
+<button type="button" title="Raw input rendered as web-page without a doctype or charset declaration" style="float: right;" onclick="javascript: sndUnproc(); return false;" onkeypress="javascript: sndUnproc(); return false;">Render in webpage</button>
+<button type="button" onclick="javascript:document.getElementById('text').focus();document.getElementById('text').select()" title="select all to copy" style="float:right;">Select all</button>
+
+<?php
+if($_w3c_validate && $validation){
+?>
+  
+<button type="button" title="HTML 4.01 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text', 'html401'); return false;" onkeypress="javascript: sndValidn('text', 'html401'); return false;">Check HTML</button>
+<button type="button" title="XHTML 1.1 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text', 'xhtml110'); return false;" onkeypress="javascript: sndValidn('text', 'xhtml110'); return false;">Check XHTML</button>
+  
+<?php
+ }
+}
+else{
+ if($_w3c_validate){
+  echo '<span style="float: right;" class="help" title="for direct submission of input or output code to W3C validator for (X)HTML validation"><span style="font-size: 85%;">&nbsp;Validator tools: </span><input type="checkbox" value="1" name="w3c_validate" id="w3c_validate" style="vertical-align: middle;"', ($validation ? ' checked="checked"' : ''), ' /></span>';
+ }
+}
+?>
+
+<span style="float:right;" class="help" title="IANA-recognized name of the input character-set; can be multiple ;- or space-separated values; may not work in some browsers"><span style="font-size: 85%;">Encoding: </span><input type="text" size="8" id="enc" name="enc" style="vertical-align: middle;" value="<?php echo htmlspecialchars($_POST['enc']); ?>" /></span>
+
+</div>
+<br style="clear:both;" />
+
+<?php
+if($limit_exceeded){
+ echo '<br /><strong>Input text is too long!</strong><br />';
+}
+?>
+
+<br />
+
+<a href="htmLawedTest.php" title="[toggle visibility] htmLawed configuration" onclick="javascript:toggle('inputC'); return false;"><span class="notice">Settings &raquo;</span></a>
+
+<div id="inputC" style="display: none;">
+<table summary="none">
+<tr>
+<td><span class="help" title="$config argument">Config:</span></td>
+<td><ul>
+<?php
+$cfg = array(
+'abs_url'=>array('3', '0', 'absolute/relative URL conversion', '-1'),
+'and_mark'=>array('2', '0', 'mark original <em>&amp;</em> chars', '0', 'd'=>1), // 'd' to disable
+'anti_link_spam'=>array('1', '0', 'modify <em>href</em> values as an anti-link spam measure', '0', array(array('30', '1', '', 'regex for extra <em>rel</em>'), array('30', '2', '', 'regex for no <em>href</em>'))),
+'anti_mail_spam'=>array('1', '0', 'replace <em>@</em> in <em>mailto:</em> URLs', '0', '8', 'NO@SPAM', 'replacement'),
+'balance'=>array('2', '1', 'fix nestings and balance tags', '0'),
+'base_url'=>array('', '', 'base URL', '25'),
+'cdata'=>array('4', 'nil', 'allow <em>CDATA</em> sections', 'nil'),
+'clean_ms_char'=>array('3', '0', 'replace bad characters introduced by Microsoft apps. like <em>Word</em>', '0'),
+'comment'=>array('4', 'nil', 'allow HTML comments', 'nil'),
+'css_expression'=>array('2', 'nil', 'allow dynamic expressions in CSS style properties', 'nil'),
+'deny_attribute'=>array('1', '0', 'denied attributes', '0', '50', '', 'these'),
+'direct_list_nest'=>array('2', 'nil', 'allow direct nesting of a list within another without requiring it to be a list item', 'nil'),
+'elements'=>array('', '', 'allowed elements', '50'),
+'hexdec_entity'=>array('3', '1', 'convert hexadecimal numeric entities to decimal ones, or vice versa', '0'),
+'hook'=>array('', '', 'name of hook function', '25'),
+'hook_tag'=>array('', '', 'name of custom function to further check attribute values', '25'),
+'keep_bad'=>array('7', '6', 'keep, or remove <em>bad</em> tag content', '0'),
+'lc_std_val'=>array('2', '1', 'lower-case std. attribute values like <em>radio</em>', '0'),
+'make_tag_strict'=>array('3', 'nil', 'transform deprecated elements', 'nil'),
+'named_entity'=>array('2', '1', 'allow named entities, or convert numeric ones', '0'),
+'no_deprecated_attr'=>array('3', '1', 'allow deprecated attributes, or transform them', '0'),
+'parent'=>array('', 'div', 'name of parent element', '25'),
+'safe'=>array('2', '0', 'for most <em>safe</em> HTML', '0'),
+'schemes'=>array('', 'href: aim, app, feed, file, ftp, gopher, http, https, irc, javascript, mailto, news, nntp, sftp, ssh, telnet, tel; *:data, file, http, https, javascript', 'allowed URL protocols', '50'),
+'show_setting'=>array('', 'htmLawed_setting', 'variable name to record <em>finalized</em> htmLawed settings', '25', 'd'=>1),
+'style_pass'=>array('2', 'nil', 'do not look at <em>style</em> attribute values', 'nil'),
+'tidy'=>array('3', '0', 'beautify/compact', '-1', '8', '1t1', 'format'),
+'unique_ids'=>array('2', '1', 'unique <em>id</em> values', '0', '8', 'my_', 'prefix'),
+'valid_xhtml'=>array('2', 'nil', 'auto-set various parameters for most valid XHTML', 'nil'),
+'xml:lang'=>array('3', 'nil', 'auto-add <em>xml:lang</em> attribute', '0'),
+);
+foreach($cfg as $k=>$v){
+ echo '<li>', $k, ': ';
+ if(!empty($v[0])){ // input radio
+  $j = intval($v[3]);
+  for($i = $j-1; ++$i < intval($v[0]) + intval($v[3]); ++$j){
+   echo '<input type="radio" name="h', $k, '" value="', $i, '"', (!isset($_POST['h'. $k]) ? ($v[1] == $i ? ' checked="checked"' : '') : ($_POST['h'. $k] == $i ? ' checked="checked"' : '')), (isset($v['d']) ? ' disabled="disabled"' : ''), ' />', $i, ' ';
+  }
+  if($v[1] == 'nil'){
+   echo '<input type="radio" name="h', $k, '" value="nil"', ((!isset($_POST['h'. $k]) or $_POST['h'. $k] == 'nil') ? ' checked="checked"' : ''), (isset($v['d']) ? ' disabled="disabled"' : ''), ' />not set ';
+  }
+  if(!empty($v[4])){ // + input text box
+   echo '<input type="radio" name="h', $k, '" value="', $j, '"', (((isset($_POST['h'. $k]) && $_POST['h'. $k] == $j) or (!isset($_POST['h'. $k]) && $j == $v[1])) ? ' checked="checked"' : ''), (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+   if(!is_array($v[4])){
+    echo $v[6], ': <input type="text" size="', $v[4], '" name="h', $k. $j, '" value="', htmlspecialchars(isset($_POST['h'. $k. $j][0]) ? $_POST['h'. $k. $j] : $v[5]), '"', (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+   }
+   else{
+    foreach($v[4] as $z){
+     echo ' ', $z[3], ': <input type="text" size="', $z[0], '" name="h', $k. $j. $z[1], '" value="', htmlspecialchars(isset($_POST['h'. $k. $j. $z[1]][0]) ? $_POST['h'. $k. $j. $z[1]] : $z[2]), '"', (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+    }    
+   }
+  }
+ }
+ elseif(ctype_digit($v[3])){ // input text
+  echo '<input type="text" size="', $v[3], '" name="h', $k, '" value="', htmlspecialchars(isset($_POST['h'. $k][0]) ? $_POST['h'. $k] : $v[1]), '"', (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';  
+ }
+ else{} // text-area
+ echo ' <span class="help">', $v[2], '</span></li>';
+}
+echo '</ul></td></tr><tr><td><span style="vertical-align: top;" class="help" title="$spec argument: element-specific attribute rules">Spec:</span></td><td><textarea name="spec" id="spec" cols="70" rows="3" style="width:80%;">', htmlspecialchars((isset($_POST['spec']) ? $_POST['spec'] : '')), '</textarea></td></tr></table>';
+?>
+
+</div>
+</form>
+
+<?php
+if($do){
+ $cfg = array();
+ foreach($_POST as $k=>$v){
+  if($k[0] == 'h' && $v != 'nil'){
+   $cfg[substr($k, 1)] = $v;
+  }
+ }
+
+ if(isset($cfg['anti_link_spam']) && $cfg['anti_link_spam'] && (!empty($cfg['anti_link_spam11']) or !empty($cfg['anti_link_spam12']))){
+  $cfg['anti_link_spam'] = array($cfg['anti_link_spam11'], $cfg['anti_link_spam12']);
+ }
+ unset($cfg['anti_link_spam11'], $cfg['anti_link_spam12']);
+ if(isset($cfg['anti_mail_spam']) && $cfg['anti_mail_spam'] == 1){
+  $cfg['anti_mail_spam'] = isset($cfg['anti_mail_spam1'][0]) ? $cfg['anti_mail_spam1'] : 0;
+ }
+ unset($cfg['anti_mail_spam11']);
+ if(isset($cfg['deny_attribute']) && $cfg['deny_attribute'] == 1){
+  $cfg['deny_attribute'] = isset($cfg['deny_attribute1'][0]) ? $cfg['deny_attribute1'] : 0;
+ }
+ unset($cfg['deny_attribute1']);
+ if(isset($cfg['tidy']) && $cfg['tidy'] == 2){
+  $cfg['tidy'] = isset($cfg['tidy2'][0]) ? $cfg['tidy2'] : 0;
+ }
+ unset($cfg['tidy2']);
+ if(isset($cfg['unique_ids']) && $cfg['unique_ids'] == 2){
+  $cfg['unique_ids'] = isset($cfg['unique_ids2'][0]) ? $cfg['unique_ids2'] : 1;
+ }
+ unset($cfg['unique_ids2']);
+ unset($cfg['and_mark']); // disabling and_mark
+
+ $cfg['show_setting'] = 'hlcfg';
+ $st = microtime(); 
+ $out = htmLawed($_POST['text'], $cfg, $_POST['spec']);
+ $et = microtime();
+ echo '<br /><a href="htmLawedTest.php" title="[toggle visibility] syntax-highlighted" onclick="javascript:toggle(\'inputR\'); return false;"><span class="notice">Input code &raquo;</span></a> <span class="help" title="tags estimated as half of total &gt; and &lt; chars; values may be inaccurate for non-ASCII text"><small><big>', strlen($_POST['text']), '</big> chars, ~<big>', ($tag = round((substr_count($_POST['text'], '>') + substr_count($_POST['text'], '<'))/2)), '</big> tag', ($tag > 1 ? 's' : ''), '</small>&nbsp;</span><div id="inputR" style="display: none;">', format($_POST['text']), '</div><script type="text/javascript">hl(\'inputR\');</script>', (!isset($_POST['text'][$_hlimit]) ? ' <a href="htmLawedTest.php" title="[toggle visibility] hexdump; non-viewable characters like line-returns are shown as dots" onclick="javascript:toggle(\'inputD\'); return false;"><span class="notice">Input binary &raquo;&nbsp;</span></a><div id="inputD" style="display: none;">'. hexdump($_POST['text']). '</div>' : ''), ' <a href="htmLawedTest.php" title="[toggle visibility] finalized internal settings as interpreted by htmLawed; for developers" onclick="javascript:toggle(\'settingF\'); return false;"><span class="notice">Finalized internal settings &raquo;&nbsp;</span></a> <div id="settingF" style="display: none;">$config: ', str_replace(array('    ', "\t", '  '), array('  ', '&nbsp;  ', '&nbsp; '), nl2br(htmlspecialchars(print_r($GLOBALS['hlcfg']['config'], true)))), '<br />$spec: ', str_replace(array('    ', "\t", '  '), array('  ', '&nbsp;  ', '&nbsp; '), nl2br(htmlspecialchars(print_r($GLOBALS['hlcfg']['spec'], true)))), '</div><script type="text/javascript">hl(\'settingF\');</script>', '<br /><a href="htmLawedTest.php" title="[toggle visibility] suitable for copy-paste" onclick="javascript:toggle(\'outputF\'); return false;"><span class="notice">Output &raquo;</span></a> <span class="help" title="approx., server-specific value excluding the \'include()\' call"><small>htmLawed processing time <big>', number_format(((substr($et,0,9)) + (substr($et,-10)) - (substr($st,0,9)) - (substr($st,-10))),4), '</big> s</small></span>', (($mem = memory_get_peak_usage()) !== false ? '<span class="help"><small>, peak memory usage <big>'. round(($mem-$pre_mem)/1048576, 2). '</big> <small>MB</small>' : ''), '</small></span><div id="outputF"  style="display: block;"><div><textarea id="text2" class="textarea" name="text2" rows="5" cols="100" style="width: 100%;">', htmlspecialchars($out), '</textarea></div><button type="button" title="Filtered input rendered as web-page without a doctype or charset declaration" style="float: right;" onclick="javascript: sndProc2(); return false;" onkeypress="javascript: sndProc2(); return false;">Render in webpage</button><button type="button" onclick="javascript:document.getElementById(\'text2\').focus();document.getElementById(\'text2\').select()" title="select all to copy" style="float:right;">Select all</button>';
+ if($_w3c_validate && $validation)
+ {
+?>
+  
+<button type="button" title="HTML 4.01 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text2', 'html401'); return false;" onkeypress="javascript: sndValidn('text2', 'html401'); return false;">Check HTML</button>
+<button type="button" title="XHTML 1.1 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text2', 'xhtml110'); return false;" onkeypress="javascript: sndValidn('text2', 'xhtml110'); return false;">Check XHTML</button>
+  
+<?php
+ }
+ echo '</div><br /><a href="htmLawedTest.php" title="[toggle visibility] syntax-highlighted" onclick="javascript:toggle(\'outputR\'); return false;"><span class="notice">Output code &raquo;</span></a><div id="outputR" style="display: block;">', format($out), '</div><script type="text/javascript">hl(\'outputR\');</script>', (!isset($_POST['text'][$_hlimit]) ? ' <a href="htmLawedTest.php" title="[toggle visibility] hexdump; non-viewable characters like line-returns are shown as dots" onclick="javascript:toggle(\'outputD\'); return false;"><span class="notice">Output binary &raquo;</span></a><div id="outputD" style="display: none;">'. hexdump($out). '</div>' : ''), ' <a href="htmLawedTest.php" title="[toggle visibility] inline output-input diff; might not be perfectly accurate, semantically or otherwise " onclick="javascript:toggle(\'diff\'); diffLaunch(); return false;"><span class="notice">Diff &raquo;</span></a> <div id="diff" style="display: none;"></div><br /><a href="htmLawedTest.php" title="[toggle visibility] XHTML 1 Transitional doctype" onclick="javascript:toggle(\'outputH\'); return false;">';
+}
+else{
+?>
+
+<br />
+
+<div class="help">Use with a Javascript- and cookie-enabled, relatively new version of a common browser.
+
+<?php echo (file_exists('./htmLawed_TESTCASE.txt') ? '<br /><br />You can use text from <a href="htmLawed_TESTCASE.txt"><span class="notice">this collection of test-cases</span></a> in the input. Set the character encoding of the browser to Unicode/utf-8 before copying.' : ''); ?>
+
+<br /><br />For anti-XSS tests, try the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawedSafeModeTest.php"><span class="notice">special test-page</span></a> or see <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/rsnake/RSnakeXSSTest.htm"><span class="notice">these results</span></a>.
+
+<br /><br /><small>Change <em>Encoding</em> to reflect the character encoding of the input text. Even then, it may not work or some characters may not display properly because of variable browser support and because of the form interface. Developers can write some PHP code to capture the filtered input to a file if this is important.
+<br /><br />Refer to the htmLawed documentation (<a href="htmLawed_README.htm"><span class="notice">htm</span></a>/<a href="htmLawed_README.txt"><span class="notice">txt</span></a>) for details about <em>Settings</em>, and htmLawed's behavior and limitations. For <em>Settings</em>, incorrectly-specified values like regular expressions are silently ignored. One or more settings form-fields may have been disabled. Some characters are not allowed in the <em>Spec</em> field.
+
+
+<br /><br />Hovering the mouse over some of the text can provide additional information in some browsers.</small>
+
+<?php
+if($_w3c_validate){
+?>
+
+<small><br /><br />Because of character-encoding issues, the W3C validator (anyway not perfect) may reject validation requests or invalidate otherwise-valid code, esp. if text was copy-pasted in the input box. Local applications like the <em>HTML Validator</em> Firefox browser add-on may be useful in such cases.</small>
+
+<?php
+}
+?>
+
+</div>
+
+<?php
+}
+?>
+
+</div>
+</body>
+</html>
diff --git a/web/libraries/htmLawed/htmLawed_README.htm b/web/libraries/htmLawed/htmLawed_README.htm
new file mode 100644 (file)
index 0000000..c2f5774
--- /dev/null
@@ -0,0 +1,2291 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta http-equiv="Content-Language" content="en" />
+<meta name="description" content="htmLawed PHP software is a free, open-source, customizable HTML input purifier and filter - htmLawed_README.txt - presented with rTxt2htm, a PHP Labware utility" />
+<meta name="keywords" content="htmLawed, HTM, HTML, HTML5, HTML 5, XHTML, XHTML5, HTML Tidy, converter, filter, formatter, purifier, sanitizer, XSS, input, PHP, software, code, script, security, cross-site scripting, hack, sanitize, remove, standards, tags, attributes, elements, Aria, Ruby, data attributes, tidy, indent, auto-indent, prettify, pretty print, htmLawed_README.txt, rTxt2htm, PHP Labware" />
+<style type="text/css" media="all">
+<!--/*--><![CDATA[/*><!--*/
+a {text-decoration:none; color: blue;}\r
+a:hover {color: red;}\r
+a:visited {color: blue;}\r
+body {margin: 0; padding: 0;}\r
+body, div, html, p {font-family: Georgia, 'Times new roman', Times;}\r
+code.code {font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}\r
+div.comment {padding: 5px; color: #999999; font-size: 80%;}\r
+div.comment a {color: #6699cc;}\r
+div#body {width: 70%; margin: 5px; padding: 5px;} /* holds non-toc content */\r
+div#toc {position: fixed; top: 5px; left: 73%; z-index: 2; margin-top: 5px; margin-left: 5px; border: 1px solid gray; padding: 5px; background-color: #ededed; width: 23%; overflow: auto; max-height:94%; font-size: 90%;} /* holds content table (toc) */\r
+div#top {font-size: 14px; margin: 5px; padding: 5px;} /* holds all content */\r
+div.monospace {overflow: auto; font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}\r
+div.sub-section {padding-left: 15px;}\r
+div.sub-sub-section {padding-left: 30px;}\r
+h1 {font-size: 22px; margin-top: 5px; margin-bottom: 5px;}\r
+h2 {font-size: 20px; float: left; margin-top: 15px; margin-bottom: 5px;}\r
+h3 {font-size: 18px; float: left; margin-top: 15px; margin-bottom: 5px;}\r
+h4 {font-size: 16px; float: left; margin-top: 15px; margin-bottom: 5px;}\r
+hr {margin-top: 15px; margin-bottom: 5px;}\r
+input, textarea {font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}\r
+p.subtle {color: gray; padding: 0; padding-top: 10px; margin: 0;}\r
+p.subtle a, p.subtle a:visited {color: #6699cc;}\r
+span.item-no {color: black;}\r
+span.subtle {color: gray; margin: 0; padding:0;}\r
+span.subtle a, span.subtle a:visited {color: #6699cc;}\r
+span.term {font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}\r
+span.toc-item {color: black;}\r
+span.totop {float: right; margin-top: 15px; margin-bottom: 5px;}\r
+span.totop a, span.totop a:visited {color: #6699cc;}\r
+@media screen { /* fixes for old IE */\r
+ * html, * html body {overflow-y: auto!important; height: 100%; margin: 0; padding: 0;}\r
+ * html div#body {height: 100%; overflow-y: auto; position: relative;}\r
+ * html div#toc {position: absolute;}\r
+}\r
+/*]]>*/-->
+</style>
+<title>htmLawed documentation | htmLawed PHP software is a free, open-source, customizable HTML input purifier and filter</title>
+</head>
+<body>
+<div id="top">
+<h1><a id="peak" name="peak"></a>htmLawed documentation</h1>
+
+<div id="toc"><span class="toc-item"><a href="#s1"><span class="item-no">1</span>&#160; About htmLawed</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.1"><span class="item-no">1.1</span>&#160; Example uses</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.2"><span class="item-no">1.2</span>&#160; Features</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.3"><span class="item-no">1.3</span>&#160; History</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.4"><span class="item-no">1.4</span>&#160; License &amp; copyright</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.5"><span class="item-no">1.5</span>&#160; Terms used here</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.6"><span class="item-no">1.6</span>&#160; Availability</a></span><br />
+<span class="toc-item"><a href="#s2"><span class="item-no">2</span>&#160; Usage</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.1"><span class="item-no">2.1</span>&#160; Simple</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.2"><span class="item-no">2.2</span>&#160; Configuring htmLawed using the <span class="term">$config</span>&#160;argument</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.3"><span class="item-no">2.3</span>&#160; Extra HTML specifications using the <span class="term">$spec</span>&#160;argument</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.4"><span class="item-no">2.4</span>&#160; Performance time &amp; memory usage</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.5"><span class="item-no">2.5</span>&#160; Some security risks to keep in mind</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.6"><span class="item-no">2.6</span>&#160; Use with <span class="term">kses()</span>&#160;code</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.7"><span class="item-no">2.7</span>&#160; Tolerance for ill-written HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.8"><span class="item-no">2.8</span>&#160; Limitations &amp; work-arounds</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.9"><span class="item-no">2.9</span>&#160; Examples of usage</a></span><br />
+<span class="toc-item"><a href="#s3"><span class="item-no">3</span>&#160; Details</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.1"><span class="item-no">3.1</span>&#160; Invalid/dangerous characters</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.2"><span class="item-no">3.2</span>&#160; Character references/entities</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.3"><span class="item-no">3.3</span>&#160; HTML elements</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.1"><span class="item-no">3.3.1</span>&#160; HTML comments &amp; <span class="term">CDATA</span>&#160;sections</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.2"><span class="item-no">3.3.2</span>&#160; Tag-transformation for better compliance with standards</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.3"><span class="item-no">3.3.3</span>&#160; Tag balancing &amp; proper nesting</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.4"><span class="item-no">3.3.4</span>&#160; Elements requiring child elements</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.5"><span class="item-no">3.3.5</span>&#160; Beautify or compact HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.4"><span class="item-no">3.4</span>&#160; Attributes</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.1"><span class="item-no">3.4.1</span>&#160; Auto-addition of XHTML-required attributes</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.2"><span class="item-no">3.4.2</span>&#160; Duplicate/invalid <span class="term">id</span>&#160;values</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.3"><span class="item-no">3.4.3</span>&#160; URL schemes &amp; scripts in attribute values</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.4"><span class="item-no">3.4.4</span>&#160; Absolute &amp; relative URLs</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.5"><span class="item-no">3.4.5</span>&#160; Lower-cased, standard attribute values</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.6"><span class="item-no">3.4.6</span>&#160; Transformation of deprecated attributes</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.7"><span class="item-no">3.4.7</span>&#160; Anti-spam &amp; <span class="term">href</span></a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.8"><span class="item-no">3.4.8</span>&#160; Inline style properties</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.9"><span class="item-no">3.4.9</span>&#160; Hook function for tag content</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.5"><span class="item-no">3.5</span>&#160; Simple configuration directive for most valid XHTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.6"><span class="item-no">3.6</span>&#160; Simple configuration directive for most <em>safe</em>&#160;HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.7"><span class="item-no">3.7</span>&#160; Using a hook function</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.8"><span class="item-no">3.8</span>&#160; Obtaining <em>finalized</em>&#160;parameter values</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.9"><span class="item-no">3.9</span>&#160; Retaining non-HTML tags in input with mixed markup</a></span><br />
+<span class="toc-item"><a href="#s4"><span class="item-no">4</span>&#160; Other</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.1"><span class="item-no">4.1</span>&#160; Support</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.2"><span class="item-no">4.2</span>&#160; Known issues</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.3"><span class="item-no">4.3</span>&#160; Change-log</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.4"><span class="item-no">4.4</span>&#160; Testing</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.5"><span class="item-no">4.5</span>&#160; Upgrade, &amp; old versions</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.6"><span class="item-no">4.6</span>&#160; Comparison with <span class="term">HTMLPurifier</span></a></span><br />
+&#160; <span class="toc-item"><a href="#s4.7"><span class="item-no">4.7</span>&#160; Use through application plug-ins/modules</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.8"><span class="item-no">4.8</span>&#160; Use in non-PHP applications</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.9"><span class="item-no">4.9</span>&#160; Donate</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.10"><span class="item-no">4.10</span>&#160; Acknowledgements</a></span><br />
+<span class="toc-item"><a href="#s5"><span class="item-no">5</span>&#160; Appendices</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.1"><span class="item-no">5.1</span>&#160; Characters discouraged in HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.2"><span class="item-no">5.2</span>&#160; Valid attribute-element combinations</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.3"><span class="item-no">5.3</span>&#160; CSS 2.1 properties accepting URLs</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.4"><span class="item-no">5.4</span>&#160; Microsoft Windows 1252 character replacements</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.5"><span class="item-no">5.5</span>&#160; URL format</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.6"><span class="item-no">5.6</span>&#160; Brief on htmLawed code</a></span></div><!-- ended div toc -->
+
+<div id="body">
+<br />
+<div class="comment">htmLawed_README.txt, 4 September 2021<br />
+htmLawed 1.2.6, 4 September 2021<br />
+Copyright Santosh Patnaik<br />
+Dual licensed with LGPL 3 and GPL 2+<br />
+A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>&#160;</div>
+<br />
+
+<div class="section"><h2>
+<a name="s1" id="s1"></a><span class="item-no">1</span>&#160; About htmLawed
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed is a PHP script to process text with HTML markup to make it more compliant with HTML standards and with administrative policies. It works by making HTML well-formed with balanced and properly nested tags, neutralizing code that introduces a security vulnerability or is used for cross-site scripting (XSS) attacks, allowing only specified HTML tags and attributes, and so on. Such <em>lawing in</em>&#160;of HTML code ensures that it is in accordance with the aesthetics, safety and usability requirements set by administrators.<br />
+<br />
+&#160; htmLawed is highly customizable, and fast with low memory usage. Its free and open-source code is in one small file. It does not require extensions or libraries, and works in older versions of PHP as well. It is a good alternative to the HTML <a href="http://tidy.sourceforge.net">Tidy</a>&#160;application.<br />
+
+<div class="sub-section"><h3>
+<a name="s1.1" id="s1.1"></a><span class="item-no">1.1</span>&#160; Example uses
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; * &#160;Filtering of text submitted as comments on blogs to allow only certain HTML elements<br />
+<br />
+&#160; * &#160;Making RSS newsfeed items standard-compliant: often one uses an excerpt from an HTML document for the content, and with unbalanced tags, non-numerical entities, etc., such excerpts may not be XML-compliant<br />
+<br />
+&#160; * &#160;Beautifying or pretty-printing HTML code<br />
+<br />
+&#160; * &#160;Text processing for stricter XML standard-compliance: e.g., to have lowercased <span class="term">x</span>&#160;in hexadecimal numeric entities becomes necessary if an HTML document with MathML content needs to be served as <span class="term">application/xml</span><br />
+<br />
+&#160; * &#160;Scraping text from web-pages<br />
+<br />
+&#160; * &#160;Transforming an HTML element to another<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.2" id="s1.2"></a><span class="item-no">1.2</span>&#160; Features
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Key: <span class="term">&#42;</span>&#160;security feature, <span class="term">^</span>&#160;standard compliance, <span class="term">~</span>&#160;requires setting right options<br />
+<br />
+&#160; htmLawed:<br />
+<br />
+&#160; * &#160;makes input more <strong>secure</strong>&#160;and <strong>standard-compliant</strong>&#160;for HTML as well as generic <strong>XML</strong>&#160;documents &#160;^<br />
+&#160; * &#160;supports markup for <strong>HTML 5</strong>&#160;and <strong>microdata, ARIA, Ruby, custom attributes</strong>, etc. &#160;^<br />
+&#160; * &#160;can <strong>beautify</strong>&#160;or <strong>compact</strong>&#160;HTML &#160;~<br />
+&#160; * &#160;works with input of almost any <strong>character encoding</strong>&#160;and does not affect it<br />
+&#160; * &#160;has good <strong>tolerance for ill-written HTML</strong><br />
+<br />
+&#160; * &#160;can enforce <strong>restricted use of elements</strong>&#160; *~<br />
+&#160; * &#160;ensures proper closure of empty elements like <span class="term">img</span>&#160; ^<br />
+&#160; * &#160;<strong>transforms deprecated elements</strong>&#160;like <span class="term">font</span>&#160; ^~<br />
+&#160; * &#160;can permit HTML <strong>comments</strong>&#160;and <strong>CDATA</strong>&#160;sections &#160;^~<br />
+&#160; * &#160;can permit all elements, including <span class="term">script</span>, <span class="term">object</span>&#160;and <span class="term">form</span>&#160; ~<br />
+<br />
+&#160; * &#160;can <strong>restrict attributes by element</strong>&#160; ^~<br />
+&#160; * &#160;removes <strong>invalid attributes</strong>&#160; ^<br />
+&#160; * &#160;lower-cases element and attribute names &#160;^<br />
+&#160; * &#160;provides <strong>required attributes</strong>, like <span class="term">alt</span>&#160;for <span class="term">image</span>&#160; ^<br />
+&#160; * &#160;<strong>transforms deprecated attributes</strong>&#160; ^~<br />
+&#160; * &#160;ensures attributes are <strong>declared only once</strong>&#160; ^<br />
+&#160; * &#160;permits <strong>custom</strong>, non-standard attributes as well as custom rules for standard attributes &#160;~<br />
+<br />
+&#160; * &#160;declares value for <em>empty</em>&#160;(<em>minimized</em>&#160;or <em>boolean</em>) attributes like <span class="term">checked</span>&#160; ^<br />
+&#160; * &#160;checks for potentially dangerous attribute values &#160;*~<br />
+&#160; * &#160;ensures <strong>unique</strong>&#160;<span class="term">id</span>&#160;attribute values &#160;^~<br />
+&#160; * &#160;<strong>double-quotes</strong>&#160;attribute values &#160;^<br />
+&#160; * &#160;lower-cases <strong>standard attribute values</strong>&#160;like <span class="term">password</span>&#160; ^<br />
+<br />
+&#160; * &#160;can restrict <strong>URL protocol/scheme by attribute</strong>&#160; *~<br />
+&#160; * &#160;can disable <strong>dynamic expressions</strong>&#160;in <span class="term">style</span>&#160;values &#160;*~<br />
+<br />
+&#160; * &#160;neutralizes invalid named <strong>character entities</strong>&#160; ^<br />
+&#160; * &#160;converts hexadecimal numeric entities to decimal ones, or vice versa &#160;^~<br />
+&#160; * &#160;converts named entities to numeric ones for generic XML use &#160;^~<br />
+<br />
+&#160; * &#160;removes <strong>null</strong>&#160;characters &#160;*<br />
+&#160; * &#160;neutralizes potentially dangerous proprietary Netscape <strong>Javascript entities</strong>&#160; *<br />
+&#160; * &#160;replaces potentially dangerous <strong>soft-hyphen</strong>&#160;character in URL-accepting attribute values with spaces &#160;*<br />
+<br />
+&#160; * &#160;removes common <strong>invalid characters</strong>&#160;not allowed in HTML or XML &#160;^<br />
+&#160; * &#160;replaces <strong>characters from Microsoft applications</strong>&#160;like <span class="term">Word</span>&#160;that are discouraged in HTML or XML &#160;^~<br />
+&#160; * &#160;neutralize entities for characters invalid or discouraged in HTML or XML &#160;^<br />
+&#160; * &#160;appropriately neutralize <span class="term">&lt;</span>, <span class="term">&amp;</span>, <span class="term">"</span>, and <span class="term">&gt;</span>&#160;characters &#160;^*<br />
+<br />
+&#160; * &#160;understands improperly spaced tag content (e.g., spread over more than a line) and properly spaces them<br />
+&#160; * &#160;attempts to <strong>balance tags</strong>&#160;for well-formedness &#160;^~<br />
+&#160; * &#160;understands when <strong>omitable closing tags</strong>&#160;like <span class="term">&lt;/p&gt;</span>&#160;are missing &#160;^~<br />
+&#160; * &#160;attempts to permit only <strong>validly nested tags</strong>&#160; ^~<br />
+&#160; * &#160;can <strong>either remove or neutralize bad content</strong>&#160;^~<br />
+&#160; * &#160;attempts to <strong>rectify common errors of plain-text misplacement</strong>&#160;(e.g., directly inside <span class="term">blockquote</span>) ^~<br />
+<br />
+&#160; * &#160;has optional <strong>anti-spam</strong>&#160;measures such as addition of <span class="term">rel="nofollow"</span>&#160;and link-disabling &#160;~<br />
+&#160; * &#160;optionally makes <strong>relative URLs absolute</strong>, and vice versa &#160;~<br />
+<br />
+&#160; * &#160;optionally marks <span class="term">&amp;</span>&#160;to identify the entities for <span class="term">&amp;</span>, <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;introduced by it &#160;~<br />
+<br />
+&#160; * &#160;allows deployment of powerful <strong>hook functions</strong>&#160;to <strong>inject</strong>&#160;HTML, <strong>consolidate</strong>&#160;<span class="term">style</span>&#160;attributes to <span class="term">class</span>, finely check attribute values, etc. &#160;~<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.3" id="s1.3"></a><span class="item-no">1.3</span>&#160; History
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed was created in 2007 for use with <span class="term">LabWiki</span>, a wiki software developed at PHP Labware, as a suitable software could not be found. Existing PHP software like <span class="term">Kses</span>&#160;and <span class="term">HTMLPurifier</span>&#160;were deemed inadequate, slow, resource-intensive, or dependent on an extension or external application like <span class="term">HTML Tidy</span>. The core logic of htmLawed, that of identifying HTML elements and attributes, was based on the <span class="term">Kses</span>&#160;(version 0.2.2) HTML filter software of Ulf Harnhammar (it can still be used with code that uses <span class="term">Kses</span>; see <a href="#s2.6">section 2.6</a>.). Support for HTML version 5 was added in May 2013 in a beta and in February 2017 in a production release.<br />
+<br />
+&#160; See <a href="#s4.3">section 4.3</a>&#160;for a detailed log of changes in htmLawed over the years, and <a href="#s4.10">section 4.10</a>&#160;for acknowledgements.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.4" id="s1.4"></a><span class="item-no">1.4</span>&#160; License &amp; copyright
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed is free and open-source software, copyrighted by Santosh Patnaik, MD, PhD, and dual-licensed with LGPL version <a href="http://www.gnu.org/licenses/lgpl-3.0.txt">3</a>, and GPL version <a href="http://www.gnu.org/licenses/gpl-2.0.txt">2</a>&#160;(or later) licenses.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.5" id="s1.5"></a><span class="item-no">1.5</span>&#160; Terms used here
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; In this document, only HTML body-level elements are considered. htmLawed does not have support for head-level elements, <span class="term">body</span>, and the frame-level elements, <span class="term">frameset</span>, <span class="term">frame</span>&#160;and <span class="term">noframes</span>, and these elements are ignored here.<br />
+<br />
+&#160; * &#160;<em>administrator</em>&#160;- or admin; person setting up the code that utilizes htmLawed; also, <em>user</em><br />
+&#160; * &#160;<em>attributes</em>&#160;- name-value pairs like <span class="term">href="http&#58;//x.com"</span>&#160;in opening tags<br />
+&#160; * &#160;<em>author</em>&#160;- see <em>writer</em><br />
+&#160; * &#160;<em>character</em>&#160;- atomic unit of text; internally represented by a numeric <em>code-point</em>&#160;as specified by the <em>encoding</em>&#160;or <em>charset</em>&#160;in use<br />
+&#160; * &#160;<em>entity</em>&#160;- markup like <span class="term">&amp;gt;</span>&#160;and <span class="term">&amp;#160;</span>&#160;used to refer to a character<br />
+&#160; * &#160;<em>element</em>&#160;- HTML element like <span class="term">a</span>&#160;and <span class="term">img</span><br />
+&#160; * &#160;<em>element content</em>&#160;- &#160;content between the opening and closing tags of an element, like <span class="term">click</span>&#160;of the <span class="term">&lt;a href="x"&gt;click&lt;/a&gt;</span>&#160;element<br />
+&#160; * &#160;<em>HTML</em>&#160;- implies XHTML unless specified otherwise<br />
+&#160; * &#160;<em>HTML body</em>&#160;- content in the <em>body</em>&#160;container of an HTML document<br />
+&#160; * &#160;<em>input</em>&#160;- text given to htmLawed to process<br />
+&#160; * &#160;<em>legal</em>&#160;– standard-compliant; also, <em>valid</em><br />
+&#160; * &#160;<em>processing</em>&#160;- involves filtering, correction, etc., of input<br />
+&#160; * &#160;<em>safe</em>&#160;- absence or reduction of certain characters and HTML elements and attributes in HTML of text that can otherwise potentially, and circumstantially, expose text readers to security vulnerabilities like cross-site scripting attacks (XSS)<br />
+&#160; * &#160;<em>scheme</em>&#160;- a URL protocol like <span class="term">http</span>&#160;and <span class="term">ftp</span><br />
+&#160; * &#160;<em>specification</em>&#160;- detailed description including rules that define HTML<br />
+&#160; * &#160;<em>standard</em>&#160;– widely accepted specification<br />
+&#160; * &#160;<em>style property</em>&#160;- terms like <span class="term">border</span>&#160;and <span class="term">height</span>&#160;for which declarations are made in values for the <span class="term">style</span>&#160;attribute of elements<br />
+&#160; * &#160;<em>tag</em>&#160;- markers like <span class="term">&lt;a href="x"&gt;</span>&#160;and <span class="term">&lt;/a&gt;</span>&#160;delineating element content; the opening tag can contain attributes<br />
+&#160; * &#160;<em>tag content</em>&#160;- consists of tag markers <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>, element names like <span class="term">div</span>, and possibly attributes<br />
+&#160; * &#160;<em>user</em>&#160;- administrator<br />
+&#160; * &#160;<em>valid</em>&#160;- see <em>legal</em><br />
+&#160; * &#160;<em>writer</em>&#160;- end-user like a blog commenter providing the input that is to be processed; also, <em>author</em><br />
+&#160; * &#160;<em>XHTML</em>&#160;- XML-compliant HTML; parsing rules for XHTML are more strict than for regular HTML<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.6" id="s1.6"></a><span class="item-no">1.6</span>&#160; Availability
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can be downloaded for free at its <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">website</a>. Besides the <span class="term">htmLawed.php</span>&#160;file, the download has the htmLawed documentation (this document) in plain <a href="htmLawed_README.txt">text</a>&#160;and <a href="htmLawed_README.htm">HTML</a>&#160;formats, a script for <a href="htmLawedTest.php">testing</a>, and a text file for <a href="htmLawed_TESTCASE.txt">test-cases</a>. htmLawed is also available as a PHP class (OOP code) at its website.<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s2" id="s2"></a><span class="item-no">2</span>&#160; Usage
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed works in PHP version 4.4 or higher. Either <span class="term">include()</span>&#160;the <span class="term">htmLawed.php</span>&#160;file, or copy-paste the entire code.<br />
+<br />
+&#160; To use with PHP 4.3, have the following code included:<br />
+<br />
+
+<code class="code">&#160; &#160; if(!function_exists(&#39;ctype_digit&#39;)){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;function ctype_digit($var){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; return ((int) $var == $var);</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;}</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+
+<div class="sub-section"><h3>
+<a name="s2.1" id="s2.1"></a><span class="item-no">2.1</span>&#160; Simple
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The input text to be processed, <span class="term">$text</span>, is passed as an argument of type string; <span class="term">htmLawed()</span>&#160;returns the processed string:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text);</code>
+<br />
+<br />
+&#160; With the <span class="term">htmLawed class</span>&#160;(<a href="#s1.6">section 1.6</a>), usage is:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed&#58;&#58;hl($text);</code>
+<br />
+<br />
+&#160; <strong>Notes</strong>: (1) If input is from a <span class="term">$_GET</span>&#160;or <span class="term">$_POST</span>&#160;value, and <span class="term">magic quotes</span>&#160;are enabled on the PHP setup, run <span class="term">stripslashes()</span>&#160;on the input before passing to htmLawed. (2) htmLawed does not have support for head-level elements, <span class="term">body</span>, and the frame-level elements, <span class="term">frameset</span>, <span class="term">frame</span>&#160;and <span class="term">noframes</span>.<br />
+<br />
+&#160; By default, htmLawed will process the text allowing all valid HTML elements/tags and commonly used URL schemes and CSS style properties. It will allow Javascript code, <span class="term">CDATA</span>&#160;sections and HTML comments, balance tags, and ensure proper nesting of elements. Such actions can be configured using two other optional arguments -- <span class="term">$config</span>&#160;and <span class="term">$spec</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config, $spec);</code>
+<br />
+<br />
+&#160; The <span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;arguments are detailed below. Some examples are shown in <a href="#s2.9">section 2.9</a>. For maximum protection against <span class="term">XSS</span>&#160;and other security vulnerabilities, consider using the <span class="term">safe</span>&#160;parameter; see <a href="#s3.6">section 3.6</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.2" id="s2.2"></a><span class="item-no">2.2</span>&#160; Configuring htmLawed using the <span class="term">$config</span>&#160;argument
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <span class="term">$config</span>&#160;instructs htmLawed on how to tackle certain tasks. When <span class="term">$config</span>&#160;is not specified, or not set as an array (e.g., <span class="term">$config = 1</span>), htmLawed will take default actions. One or many of the task-action or parameter-value pairs can be specified in <span class="term">$config</span>&#160;as array key-value pairs. If a parameter is not specified, htmLawed will use the default value for it, indicated further below. In PHP code, parameter values that are integers should not be quoted and should be used as numeric types (unless meant as string/text). Thus, for instance:<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;comment&#39;=&gt;0, &#39;cdata&#39;=&gt;1, &#39;elements&#39;=&gt;&#39;a, b, strong&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config);</code>
+<br />
+<br />
+&#160; Below are the various parameters that can be specified in <span class="term">$config</span>.<br />
+<br />
+&#160; Key: <span class="term">&#42;</span>&#160;default, <span class="term">^</span>&#160;different from htmLawed versions below 1.2, <span class="term">~</span>&#160;different default when <span class="term">valid_xhtml</span>&#160;is set to <span class="term">1</span>&#160;(see <a href="#s3.5">section 3.5</a>), <span class="term">"</span>&#160;different default when <span class="term">safe</span>&#160;is set to <span class="term">1</span>&#160;(see <a href="#s3.6">section 3.6</a>)<br />
+<br />
+&#160; <strong>abs_url</strong><br />
+&#160; Make URLs absolute or relative; <span class="term">$config["base_url"]</span>&#160;needs to be set; see <a href="#s3.4.4">section 3.4.4</a><br />
+<br />
+&#160; <span class="term">-1</span>&#160;- make relative<br />
+&#160; <span class="term">0</span>&#160;- no action &#160;*<br />
+&#160; <span class="term">1</span>&#160;- make absolute<br />
+<br />
+&#160; <strong>and_mark</strong><br />
+&#160; Mark <span class="term">&amp;</span>&#160;characters in the original input; see <a href="#s3.2">section 3.2</a><br />
+<br />
+&#160; <strong>anti_link_spam</strong><br />
+&#160; Anti-link-spam measure; see <a href="#s3.4.7">section 3.4.7</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no measure taken &#160;*<br />
+&#160; <em>array("regex1", "regex2")</em>&#160;- will ensure a <span class="term">rel</span>&#160;attribute with <span class="term">nofollow</span>&#160;in its value in case the <span class="term">href</span>&#160;attribute value matches the regular expression pattern <span class="term">regex1</span>, and/or will remove <span class="term">href</span>&#160;if its value matches the regular expression pattern <span class="term">regex2</span>. E.g., <span class="term">array("/./", "/&#58;//\W&#42;(?!(abc\.com|xyz\.org))/")</span>; see <a href="#s3.4.7">section 3.4.7</a>&#160;for more.<br />
+<br />
+&#160; <strong>anti_mail_spam</strong><br />
+&#160; Anti-mail-spam measure; see <a href="#s3.4.7">section 3.4.7</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no measure taken &#160;*<br />
+&#160; <em>word</em>&#160;- <span class="term">@</span>&#160;in mail address in <span class="term">href</span>&#160;attribute value is replaced with specified <em>word</em><br />
+<br />
+&#160; <strong>balance</strong><br />
+&#160; Balance tags for well-formedness and proper nesting; see <a href="#s3.3.3">section 3.3.3</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes &#160;*<br />
+<br />
+&#160; <strong>base_url</strong><br />
+&#160; Base URL value that needs to be set if <span class="term">$config["abs_url"]</span>&#160;is not <span class="term">0</span>; see <a href="#s3.4.4">section 3.4.4</a><br />
+<br />
+&#160; <strong>cdata</strong><br />
+&#160; Handling of <span class="term">CDATA</span>&#160;sections; see <a href="#s3.3.1">section 3.3.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- don't consider <span class="term">CDATA</span>&#160;sections as markup and proceed as if plain text &#160;"<br />
+&#160; <span class="term">1</span>&#160;- remove<br />
+&#160; <span class="term">2</span>&#160;- allow, but neutralize any <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;inside by converting them to named entities<br />
+&#160; <span class="term">3</span>&#160;- allow &#160;*<br />
+<br />
+&#160; <strong>clean_ms_char</strong><br />
+&#160; Replace <em>discouraged</em>&#160;characters introduced by Microsoft Word, etc.; see <a href="#s3.1">section 3.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- yes<br />
+&#160; <span class="term">2</span>&#160;- yes, but replace special single &amp; double quotes with ordinary ones<br />
+<br />
+&#160; <strong>comment</strong><br />
+&#160; Handling of HTML comments; see <a href="#s3.3.1">section 3.3.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- don't consider comments as markup and proceed as if plain text &#160;"<br />
+&#160; <span class="term">1</span>&#160;- remove<br />
+&#160; <span class="term">2</span>&#160;- allow, but neutralize any <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;inside by converting to named entities<br />
+&#160; <span class="term">3</span>&#160;- allow &#160;*<br />
+<br />
+&#160; <strong>css_expression</strong><br />
+&#160; Allow dynamic CSS expression by not removing the expression from CSS property values in <span class="term">style</span>&#160;attributes; see <a href="#s3.4.8">section 3.4.8</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- remove &#160;*<br />
+&#160; <span class="term">1</span>&#160;- allow<br />
+<br />
+&#160; <strong>deny_attribute</strong><br />
+&#160; Denied HTML attributes; see <a href="#s3.4">section 3.4</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- none &#160;*<br />
+&#160; <em>string</em>&#160;- dictated by values in <em>string</em><br />
+&#160; <span class="term">on&#42;</span>&#160;- on* event attributes like <span class="term">onfocus</span>&#160;not allowed &#160;"<br />
+<br />
+&#160; <strong>direct_nest_list</strong><br />
+&#160; Allow direct nesting of a list within another without requiring it to be a list item; see <a href="#s3.3.4">section 3.3.4</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- yes<br />
+<br />
+&#160; <strong>elements</strong><br />
+&#160; Allowed HTML elements; see <a href="#s3.3">section 3.3</a><br />
+<br />
+&#160; <em>all</em>&#160;- *^<br />
+&#160; <span class="term">&#42; -acronym -big -center -dir -font -isindex -s -strike -tt</span>&#160;- &#160;~^<br />
+&#160; <em>applet, audio, canvas, embed, iframe, object, script, and video elements not allowed</em>&#160;- &#160;"^<br />
+<br />
+&#160; <strong>hexdec_entity</strong><br />
+&#160; Allow hexadecimal numeric entities and do not convert to the more widely accepted decimal ones, or convert decimal to hexadecimal ones; see <a href="#s3.2">section 3.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes &#160;*<br />
+&#160; <span class="term">2</span>&#160;- convert decimal to hexadecimal ones<br />
+<br />
+&#160; <strong>hook</strong><br />
+&#160; Name of an optional hook function to alter the input string, <span class="term">$config</span>&#160;or <span class="term">$spec</span>&#160;before htmLawed enters the main phase of its work; see <a href="#s3.7">section 3.7</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no hook function &#160;*<br />
+&#160; <em>name</em>&#160;- <em>name</em>&#160;is name of the hook function<br />
+<br />
+&#160; <strong>hook_tag</strong><br />
+&#160; Name of an optional hook function to alter tag content finalized by htmLawed; see <a href="#s3.4.9">section 3.4.9</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no hook function &#160;*<br />
+&#160; <em>name</em>&#160;- <em>name</em>&#160;is name of the hook function<br />
+<br />
+&#160; <strong>keep_bad</strong><br />
+&#160; Neutralize <em>bad</em>&#160;tags by converting their <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;characters to entities, or remove them; see <a href="#s3.3.3">section 3.3.3</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- remove<br />
+&#160; <span class="term">1</span>&#160;- neutralize both tags and element content<br />
+&#160; <span class="term">2</span>&#160;- remove tags but neutralize element content<br />
+&#160; <span class="term">3</span>&#160;and <span class="term">4</span>&#160;- like <span class="term">1</span>&#160;and <span class="term">2</span>&#160;but remove if text (<span class="term">pcdata</span>) is invalid in parent element<br />
+&#160; <span class="term">5</span>&#160;and <span class="term">6</span>&#160;* - &#160;like <span class="term">3</span>&#160;and <span class="term">4</span>&#160;but line-breaks, tabs and spaces are left<br />
+<br />
+&#160; <strong>lc_std_val</strong><br />
+&#160; For XHTML compliance, predefined, standard attribute values, like <span class="term">get</span>&#160;for the <span class="term">method</span>&#160;attribute of <span class="term">form</span>, must be lowercased; see <a href="#s3.4.5">section 3.4.5</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes &#160;*<br />
+<br />
+&#160; <strong>make_tag_strict</strong><br />
+&#160; Transform or remove these deprecated HTML elements, even if they are allowed by the admin: acronym, applet, big, center, dir, font, isindex, s, strike, tt; see <a href="#s3.3.2">section 3.3.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes, but leave <span class="term">applet</span>&#160;and <span class="term">isindex</span>&#160;that currently cannot be transformed &#160;*^<br />
+&#160; <span class="term">2</span>&#160;- yes, removing <span class="term">applet</span>&#160;and <span class="term">isindex</span>&#160;elements and their contents (nested elements remain) &#160;~^<br />
+<br />
+&#160; <strong>named_entity</strong><br />
+&#160; Allow non-universal named HTML entities, or convert to numeric ones; see <a href="#s3.2">section 3.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- convert<br />
+&#160; <span class="term">1</span>&#160;- allow &#160;*<br />
+<br />
+&#160; <strong>no_deprecated_attr</strong><br />
+&#160; Allow deprecated attributes or transform them; see <a href="#s3.4.6">section 3.4.6</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- allow<br />
+&#160; <span class="term">1</span>&#160;- transform, but <span class="term">name</span>&#160;attributes for <span class="term">a</span>&#160;and <span class="term">map</span>&#160;are retained &#160;*<br />
+&#160; <span class="term">2</span>&#160;- transform<br />
+<br />
+&#160; <strong>parent</strong><br />
+&#160; Name of the parent element, possibly imagined, that will hold the input; see <a href="#s3.3">section 3.3</a><br />
+<br />
+&#160; <strong>safe</strong><br />
+&#160; Magic parameter to make input the most secure against vulnerabilities like XSS without needing to specify other relevant <span class="term">$config</span>&#160;parameters; see <a href="#s3.6">section 3.6</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- will auto-adjust other relevant <span class="term">$config</span>&#160;parameters (indicated by <span class="term">"</span>&#160;in this list) &#160;^<br />
+<br />
+&#160; <strong>schemes</strong><br />
+&#160; Array of attribute-specific, comma-separated, lower-cased list of schemes (protocols) allowed in attributes accepting URLs (or <span class="term">!</span>&#160;to <em>deny</em>&#160;any URL); <span class="term">&#42;</span>&#160;covers all unspecified attributes; see <a href="#s3.4.3">section 3.4.3</a><br />
+<br />
+&#160; <span class="term">href&#58; aim, app, feed, file, ftp, gopher, http, https, javascript, irc, mailto, news, nntp, sftp, ssh, tel, telnet; &#42;&#58;data, file, http, https, javascript</span>&#160; *^<br />
+&#160; <span class="term">href&#58; aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet; style&#58; !; &#42;&#58;file, http, https</span>&#160; "<br />
+<br />
+&#160; <strong>show_setting</strong><br />
+&#160; Name of a PHP variable to assign the <em>finalized</em>&#160;<span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;values; see <a href="#s3.8">section 3.8</a><br />
+<br />
+&#160; <strong>style_pass</strong><br />
+&#160; Ignore <span class="term">style</span>&#160;attribute values, letting them through without any alteration<br />
+<br />
+&#160; <span class="term">0</span>&#160;- no *<br />
+&#160; <span class="term">1</span>&#160;- htmLawed will let through any <span class="term">style</span>&#160;value; see <a href="#s3.4.8">section 3.4.8</a><br />
+<br />
+&#160; <strong>tidy</strong><br />
+&#160; Beautify or compact HTML code; see <a href="#s3.3.5">section 3.3.5</a><br />
+<br />
+&#160; <span class="term">-1</span>&#160;- compact<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;or <em>string</em>&#160;- beautify (custom format specified by <span class="term">string</span>)<br />
+<br />
+&#160; <strong>unique_ids</strong><br />
+&#160; <span class="term">id</span>&#160;attribute value checks; see <a href="#s3.4.2">section 3.4.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- remove duplicate and/or invalid ones &#160;*<br />
+&#160; <em>word</em>&#160;- remove invalid ones and replace duplicate ones with new and unique ones based on the <em>word</em>; the admin-specified <em>word</em>&#160;cannot contain a space character<br />
+<br />
+&#160; <strong>valid_xhtml</strong><br />
+&#160; Magic parameter to make input the most valid XHTML without needing to specify other relevant <span class="term">$config</span>&#160;parameters; see <a href="#s3.5">section 3.5</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- will auto-adjust other relevant <span class="term">$config</span>&#160;parameters (indicated by <span class="term">~</span>&#160;in this list)<br />
+<br />
+&#160; <strong>xml:lang</strong><br />
+&#160; Auto-add <span class="term">xml&#58;lang</span>&#160;attribute; see <a href="#s3.4.1">section 3.4.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- add if <span class="term">lang</span>&#160;attribute is present<br />
+&#160; <span class="term">2</span>&#160;- add if <span class="term">lang</span>&#160;attribute is present, and remove <span class="term">lang</span>&#160; ~<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.3" id="s2.3"></a><span class="item-no">2.3</span>&#160; Extra HTML specifications using the $spec parameter
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The <span class="term">$spec</span>&#160;argument of htmLawed can be used to disallow an otherwise legal attribute for an element, or to restrict the attribute's values. This can also be helpful as a security measure (e.g., in certain versions of browsers, certain values can cause buffer overflows and denial of service attacks), or in enforcing admin policies. <span class="term">$spec</span>&#160;is specified as a string of text containing one or more <em>rules</em>, with multiple rules separated from each other by a semi-colon (<span class="term">;</span>). E.g.,<br />
+<br />
+
+<code class="code">&#160; &#160; $spec = &#39;i=-&#42;; td, tr=style, id, -&#42;; a=id(match="/[a-z][a-z\d.&#58;\-&#96;"]&#42;/i"/minval=2), href(maxlen=100/minlen=34); img=-width,-alt&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config, $spec);</code>
+<br />
+<br />
+&#160; Or,<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config, &#39;i=-&#42;; td, tr=style, id, -&#42;; a=id(match="/[a-z][a-z\d.&#58;\-&#96;"]&#42;/i"/minval=2), href(maxlen=100/minlen=34); img=-width,-alt&#39;);</code>
+<br />
+<br />
+&#160; A rule begins with an HTML <strong>element</strong>&#160;name(s) (<em>rule-element</em>), for which the rule applies, followed by an equal-to (=) sign. A rule-element may represent multiple elements if comma (,)-separated element names are used. E.g., <span class="term">th,td,tr=</span>.<br />
+<br />
+&#160; Rest of the rule consists of comma-separated HTML <strong>attribute names</strong>. A minus (-) character before an attribute means that the attribute is not permitted inside the rule-element. E.g., <span class="term">-width</span>. To deny all attributes, <span class="term">-&#42;</span>&#160;can be used.<br />
+<br />
+&#160; Following shows examples of rule excerpts with rule-element <span class="term">a</span>&#160;and the attributes that are being permitted:<br />
+<br />
+&#160; * &#160;<span class="term">a=</span>&#160;- all<br />
+&#160; * &#160;<span class="term">a=id</span>&#160;- all<br />
+&#160; * &#160;<span class="term">a=href, title, -id, -onclick</span>&#160;- all except <span class="term">id</span>&#160;and <span class="term">onclick</span><br />
+&#160; * &#160;<span class="term">a=&#42;, id, -id</span>&#160;- all except <span class="term">id</span><br />
+&#160; * &#160;<span class="term">a=-&#42;</span>&#160;- none<br />
+&#160; * &#160;<span class="term">a=-&#42;, href, title</span>&#160;- none except <span class="term">href</span>&#160;and <span class="term">title</span><br />
+&#160; * &#160;<span class="term">a=-&#42;, -id, href, title</span>&#160;- none except <span class="term">href</span>&#160;and <span class="term">title</span><br />
+<br />
+&#160; Rules regarding <strong>attribute values</strong>&#160;are optionally specified inside round brackets after attribute names in solidus (/)-separated <em>parameter = value</em>&#160;pairs. E.g., <span class="term">title(maxlen=30/minlen=5)</span>. None or one or more of the following parameters may be specified:<br />
+<br />
+&#160; * &#160;<span class="term">oneof</span>&#160;- one or more choices separated by <span class="term">|</span>&#160;that the value should match; if only one choice is provided, then the value must match that choice; matching is case-sensitive<br />
+<br />
+&#160; * &#160;<span class="term">noneof</span>&#160;- one or more choices separated by <span class="term">|</span>&#160;that the value should not match; matching is case-sensitive<br />
+<br />
+&#160; * &#160;<span class="term">maxlen</span>&#160;and <span class="term">minlen</span>&#160;- upper and lower limits for the number of characters in the attribute value; specified in numbers<br />
+<br />
+&#160; * &#160;<span class="term">maxval</span>&#160;and <span class="term">minval</span>&#160;- upper and lower limits for the numerical value specified in the attribute value; specified in numbers<br />
+<br />
+&#160; * &#160;<span class="term">match</span>&#160;and <span class="term">nomatch</span>&#160;- pattern that the attribute value should or should not match; specified as PHP/PCRE-compatible regular expressions with delimiters and possibly modifiers (e.g., to specify case-sensitivity for matching)<br />
+<br />
+&#160; * &#160;<span class="term">default</span>&#160;- a value to force on the attribute if the value provided by the writer does not fit any of the specified parameters<br />
+<br />
+&#160; If <span class="term">default</span>&#160;is not set and the attribute value does not satisfy any of the specified parameters, then the attribute is removed. The <span class="term">default</span>&#160;value can also be used to force all attribute declarations to take the same value (by getting the values declared illegal by setting, e.g., <span class="term">maxlen</span>&#160;to <span class="term">-1</span>).<br />
+<br />
+&#160; Examples with <em>input</em>&#160;<span class="term">&lt;input title="WIDTH" value="10em" /&gt;&lt;input title="length" value="5" class="ic1 ic2" /&gt;</span>&#160;are shown below.<br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(maxlen=60/minlen=6), value</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input value="10em" /&gt;&lt;input title="length" value="5" class="ic1 ic2" /&gt;</span><br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(), value(maxval=8/default=6)</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input title="WIDTH" value="6" /&gt;&lt;input title="length" value="5" class="ic1 ic2" /&gt;</span><br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(nomatch=%w.d%i), value(match=%em%/default=6em)</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input value="10em" /&gt;&lt;input title="length" value="6em" class="ic1 ic2" /&gt;</span><br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=class(noneof=ic2|ic3/oneof=ic1|ic4), title(oneof=height|depth/default=depth), value(noneof=5|6)</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input title="depth" value="10em" /&gt;&lt;input title="depth" class="ic1" /&gt;</span><br />
+<br />
+&#160; <strong>Special characters</strong>: The characters <span class="term">;</span>, <span class="term">,</span>, <span class="term">/</span>, <span class="term">(</span>, <span class="term">)</span>, <span class="term">|</span>, <span class="term">~</span>&#160;and space have special meanings in the rules. Words in the rules that use such characters, or the characters themselves, should be <em>escaped</em>&#160;by enclosing in pairs of double-quotes (<span class="term">"</span>). A back-tick (<span class="term">&#96;</span>) can be used to escape a literal <span class="term">"</span>. An example rule illustrating this is <span class="term">input=value(maxlen=30/match="/^\w/"/default="your &#96;"ID&#96;"")</span>.<br />
+<br />
+&#160; <strong>Attributes that accept multiple values</strong>: If an attribute is <span class="term">accesskey</span>, <span class="term">class</span>, <span class="term">itemtype</span>&#160;or <span class="term">rel</span>, which can have multiple, space-separated values, or <span class="term">srcset</span>, which can have multiple, comma-separated values, htmLawed will parse the attribute value for such multiple values and will individually test each of them.<br />
+<br />
+&#160; <strong>Note</strong>: To deny an attribute for all elements for which it is legal, <span class="term">$config["deny_attribute"]</span>&#160;(see <a href="#s3.4">section 3.4</a>) can be used instead of <span class="term">$spec</span>. Also, attributes can be allowed element-specifically through <span class="term">$spec</span>&#160;while being denied globally through <span class="term">$config["deny_attribute"]</span>. The <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) can also be possibly used to implement a functionality like that achieved using <span class="term">$spec</span>&#160;functionality.<br />
+<br />
+&#160; <strong>Note</strong>: Attributes' specifications for an element may be set through multiple rules. In case of conflict, the attribute specification in the first rule will get precedence.<br />
+<br />
+&#160; <span class="term">$spec</span>&#160;can also be used to permit custom, non-standard attributes as well as custom rules for standard attributes. Thus, the following value of <span class="term">$spec</span>&#160;will permit the custom uses of the standard <span class="term">rel</span>&#160;attribute in <span class="term">input</span>&#160;(not permitted as per standards) and of a non-standard attribute, <span class="term">vFlag</span>, in <span class="term">img</span>.<br />
+<br />
+
+<code class="code">&#160; &#160; $spec = &#39;img=vFlag; input=rel&#39;</code>
+<br />
+<br />
+&#160; The attribute names must begin with an alphabet and cannot have space, equal-to (=) and solidus (/) characters.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.4" id="s2.4"></a><span class="item-no">2.4</span>&#160; Performance time &amp; memory usage
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The time and memory consumed during text processing by htmLawed depends on its configuration, the size of the input, and the amount, nestedness and well-formedness of the HTML markup within the input. In particular, tag balancing and beautification each can increase the processing time by about a quarter.<br />
+<br />
+&#160; The htmLawed <a href="htmLawedTest.php">demo</a>&#160;can be used to evaluate the performance and effects of different types of input and <span class="term">$config</span>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.5" id="s2.5"></a><span class="item-no">2.5</span>&#160; Some security risks to keep in mind
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; When setting the parameters/arguments (like those to allow certain HTML elements) for use with htmLawed, one should bear in mind that the setting may let through potentially <em>dangerous</em>&#160;HTML code which is meant to steal user-data, deface a website, render a page non-functional, etc. Unless end-users, either people or software, supplying the content are completely trusted, security issues arising from the degree of HTML usage permitted through htmLawed's setting should be considered. For example, following increase security risks:<br />
+<br />
+&#160; * &#160;Allowing <span class="term">script</span>, <span class="term">applet</span>, <span class="term">embed</span>, <span class="term">iframe</span>, <span class="term">canvas</span>, <span class="term">audio</span>, <span class="term">video</span>&#160;or <span class="term">object</span>&#160;elements, or certain of their attributes like <span class="term">allowscriptaccess</span><br />
+<br />
+&#160; * &#160;Allowing HTML comments (some Internet Explorer versions are vulnerable with, e.g., <span class="term">&lt;!--[if gte IE 4]&gt;&lt;script&gt;alert("xss");&lt;/script&gt;&lt;![endif]--&gt;</span><br />
+<br />
+&#160; * &#160;Allowing dynamic CSS expressions (some Internet Explorer versions are vulnerable)<br />
+<br />
+&#160; * &#160;Allowing the <span class="term">style</span>&#160;attribute<br />
+<br />
+&#160; To remove <em>unsecure</em>&#160;HTML, code-developers using htmLawed must set <span class="term">$config</span>&#160;appropriately. E.g., <span class="term">$config["elements"] = "&#42; -script"</span>&#160;to deny the <span class="term">script</span>&#160;element (<a href="#s3.3">section 3.3</a>), <span class="term">$config["safe"] = 1</span>&#160;to auto-configure ceratin htmLawed parameters for maximizing security (<a href="#s3.6">section 3.6</a>), etc.<br />
+<br />
+&#160; Permitting the <span class="term">&#42;style&#42;</span>&#160;attribute brings in risks of <em>click-jacking</em>, <em>phishing</em>, web-page overlays, etc., <em>even</em>&#160;when the <span class="term">safe</span>&#160;parameter is enabled (see <a href="#s3.6">section 3.6</a>). Except for URLs and a few other things like CSS dynamic expressions, htmLawed currently does not check every CSS style property. It does provide ways for the code-developer implementing htmLawed to do such checks through htmLawed's <span class="term">$spec</span>&#160;argument, and through the <span class="term">hook_tag</span>&#160;parameter (see <a href="#s3.4.8">section 3.4.8</a>&#160;for more). Disallowing <span class="term">style</span>&#160;completely and relying on CSS classes and stylesheet files is recommended.<br />
+<br />
+&#160; htmLawed does not check or correct the character <strong>encoding</strong>&#160;of the input it receives. In conjunction with permissive circumstances, such as when the character encoding is left undefined through HTTP headers or HTML <span class="term">meta</span>&#160;tags, this can allow for an exploit (like Google's <em>UTF-7/XSS</em>&#160;vulnerability of the past).<br />
+<br />
+&#160; Ocassionally, though very rarely, the default settings with which htmLawed runs may change between different versions of htmLawed. Admins should keep this in mind when upgrading htmLawed. Important changes in htmLawed's default behavior in new releases of the software are noted in <a href="#s4.5">section 4.5</a>&#160;on upgrades.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.6" id="s2.6"></a><span class="item-no">2.6</span>&#160; Use with <span class="term">kses()</span>&#160;code
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The <span class="term">Kses</span>&#160;PHP script for HTML filtering is used by many applications (like <span class="term">WordPress</span>, as in year 2012). It is possible to have such applications use htmLawed instead, since it is compatible with code that calls the <span class="term">kses()</span>&#160;function declared in the <span class="term">Kses</span>&#160;file (usually named <span class="term">kses.php</span>). E.g., application code like this will continue to work after replacing <span class="term">Kses</span>&#160;with htmLawed:<br />
+<br />
+
+<code class="code">&#160; &#160; $comment_filtered = kses($comment_input, array(&#39;a&#39;=&gt;array(), &#39;b&#39;=&gt;array(), &#39;i&#39;=&gt;array()));</code>
+<br />
+<br />
+&#160; If the application uses a <span class="term">Kses</span>&#160;file that has the <span class="term">kses()</span>&#160;function declared, then, to have the application use htmLawed instead of <span class="term">Kses</span>, rename <span class="term">htmLawed.php</span>&#160;(to <span class="term">kses.php</span>, e.g.) and replace the <span class="term">Kses</span>&#160;file (or just replace the code in the <span class="term">Kses</span>&#160;file with the htmLawed code). If the <span class="term">kses()</span>&#160;function in the <span class="term">Kses</span>&#160;file had been renamed by the application developer (e.g., in <span class="term">WordPress</span>, it is named <span class="term">wp_kses()</span>), then appropriately rename the <span class="term">kses()</span>&#160;function in the htmLawed code. Then, add the following code (which was a part of htmLawed prior to version 1.2):<br />
+<br />
+
+<code class="code">&#160; &#160; // kses compatibility</code>
+<br />
+
+<code class="code">&#160; &#160; function kses($t, $h, $p=array(&#39;http&#39;, &#39;https&#39;, &#39;ftp&#39;, &#39;news&#39;, &#39;nntp&#39;, &#39;telnet&#39;, &#39;gopher&#39;, &#39;mailto&#39;)){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;foreach($h as $k=&gt;$v){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; $h[$k][&#39;n&#39;][&#39;&#42;&#39;] = 1;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;}</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$C[&#39;cdata&#39;] = $C[&#39;comment&#39;] = $C[&#39;make_tag_strict&#39;] = $C[&#39;no_deprecated_attr&#39;] = $C[&#39;unique_ids&#39;] = 0;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$C[&#39;keep_bad&#39;] = 1;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$C[&#39;elements&#39;] = count($h) ? strtolower(implode(&#39;,&#39;, array_keys($h))) &#58; &#39;-&#42;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$C[&#39;hook&#39;] = &#39;kses_hook&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$C[&#39;schemes&#39;] = &#39;&#42;&#58;&#39;. implode(&#39;,&#39;, $p);</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;return htmLawed($t, $C, $h);</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;}</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; function kses_hook($t, &amp;$C, &amp;$S){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;return $t;</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+<br />
+&#160; If the <span class="term">Kses</span>&#160;file used by the application has been significantly altered by the application developers, then one may need a different approach. E.g., with <span class="term">WordPress</span>&#160;(as in the year 2012), it is best to copy the htmLawed code, along with the above-mentioned additions, to <span class="term">wp_includes/kses.php</span>, rename the newly added function <span class="term">kses()</span>&#160;to <span class="term">wp_kses()</span>, and delete the code for the original <span class="term">wp_kses()</span>&#160;function.<br />
+<br />
+&#160; If the <span class="term">Kses</span>&#160;code has a non-empty hook function (e.g., <span class="term">wp_kses_hook()</span>&#160;in case of <span class="term">WordPress</span>), then the code for htmLawed's <span class="term">kses_hook()</span>&#160;function should be appropriately edited. However, the requirement of the hook function should be re-evaluated considering that htmLawed has extra capabilities. With <span class="term">WordPress</span>, the hook function is an essential one. The following code is suggested for the htmLawed <span class="term">kses_hook()</span>&#160;in case of <span class="term">WordPress</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; // kses compatibility</code>
+<br />
+
+<code class="code">&#160; &#160; function kses_hook($string, &amp;$cf, &amp;$spec){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$allowed_html = $spec;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;$allowed_protocols = array();</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;foreach($cf[&#39;schemes&#39;] as $v){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; foreach($v as $k2=&gt;$v2){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;if(!in_array($k2, $allowed_protocols)){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; $allowed_protocols[] = $k2;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;}</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;}</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;return wp_kses_hook($string, $allowed_html, $allowed_protocols);</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.7" id="s2.7"></a><span class="item-no">2.7</span>&#160; Tolerance for ill-written HTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can work with ill-written HTML code in the input. However, HTML that is too ill-written may not be <em>read</em>&#160;as HTML, and may therefore get identified as mere plain text. Following statements indicate the degree of <em>looseness</em>&#160;that htmLawed can work with, and can be provided in instructions to writers:<br />
+<br />
+&#160; * &#160;Tags must be flanked by <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;with no <span class="term">&gt;</span>&#160;inside -- any needed <span class="term">&gt;</span>&#160;should be put in as <span class="term">&amp;gt;</span>. It is possible for tag content (element name and attributes) to be spread over many lines instead of being on one. A space may be present between the tag content and <span class="term">&gt;</span>, like <span class="term">&lt;div &gt;</span>&#160;and <span class="term">&lt;img / &gt;</span>, but not after the <span class="term">&lt;</span>.<br />
+<br />
+&#160; * &#160;Element and attribute names need not be lower-cased.<br />
+<br />
+&#160; * &#160;Attribute string of elements may be liberally spaced with tabs, line-breaks, etc.<br />
+<br />
+&#160; * &#160;Attribute values may be single- and not double-quoted.<br />
+<br />
+&#160; * &#160;Left-padding of numeric entities (like, <span class="term">&amp;#0160;</span>, <span class="term">&amp;x07ff;</span>) with <span class="term">0</span>&#160;is okay as long as the number of characters between between the <span class="term">&amp;</span>&#160;and the <span class="term">;</span>&#160;does not exceed 8. All entities must end with <span class="term">;</span>&#160;though.<br />
+<br />
+&#160; * &#160;Named character entities must be properly cased. Thus, <span class="term">&amp;Lt;</span>&#160;or <span class="term">&amp;TILDE;</span>&#160;will not be recognized as entities and will be <em>neutralized</em>.<br />
+<br />
+&#160; * &#160;HTML comments should not be inside element tags (they can be between tags), and should begin with <span class="term">&lt;!--</span>&#160;and end with <span class="term">--&gt;</span>. Characters like <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;may be allowed inside depending on <span class="term">$config</span>, but any <span class="term">--&gt;</span>&#160;inside should be put in as <span class="term">--&amp;gt;</span>. Any <span class="term">--</span>&#160;inside will be automatically converted to <span class="term">-</span>, and a space will be added before the <span class="term">--&gt;</span>&#160;comment-closing marker &#160;unless <span class="term">$config["comments"]</span>&#160;is set to <span class="term">4</span>&#160;(<a href="#s3.3.1">section 3.3.1</a>).<br />
+<br />
+&#160; * &#160;<span class="term">CDATA</span>&#160;sections should not be inside element tags, and can be in element content only if plain text is allowed for that element. They should begin with <span class="term">&lt;[CDATA[</span>&#160;and end with <span class="term">]]&gt;</span>. Characters like <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;may be allowed inside depending on <span class="term">$config</span>, but any <span class="term">]]&gt;</span>&#160;inside should be put in as <span class="term">]]&amp;gt;</span>.<br />
+<br />
+&#160; * &#160;For attribute values, character entities <span class="term">&amp;lt;</span>, <span class="term">&amp;gt;</span>&#160;and <span class="term">&amp;amp;</span>&#160;should be used instead of characters <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;(when <span class="term">&amp;</span>&#160;is not part of a character entity). This applies even for Javascript code in values of attributes like <span class="term">onclick</span>.<br />
+<br />
+&#160; * &#160;Characters <span class="term">&lt;</span>, <span class="term">&gt;</span>, <span class="term">&amp;</span>&#160;and <span class="term">"</span>&#160;that are part of actual Javascript, etc., code in <span class="term">script</span>&#160;elements should be used as such and not be put in as entities like <span class="term">&amp;gt;</span>. Otherwise, though the HTML will be valid, the code may fail to work. Further, if such characters have to be used, then they should be put inside <span class="term">CDATA</span>&#160;sections.<br />
+<br />
+&#160; * &#160;Simple instructions like "an opening tag cannot be present between two closing tags" and "nested elements should be closed in the reverse order of how they were opened" can help authors write balanced HTML. If tags are imbalanced, htmLawed will try to balance them, but in the process, depending on <span class="term">$config["keep_bad"]</span>, some code/text may be lost.<br />
+<br />
+&#160; * &#160;Input authors should be notified of admin-specified allowed elements, attributes, configuration values (like conversion of named entities to numeric ones), etc.<br />
+<br />
+&#160; * &#160;With <span class="term">$config["unique_ids"]</span>&#160;not <span class="term">0</span>&#160;and the <span class="term">id</span>&#160;attribute being permitted, writers should carefully avoid using duplicate or invalid <span class="term">id</span>&#160;values as even though htmLawed will correct/remove the values, the final output may not be the one desired. E.g., when <span class="term">&lt;a id="home"&gt;&lt;/a&gt;&lt;input id="home" /&gt;&lt;label for="home"&gt;&lt;/label&gt;</span>&#160;is processed into<br />
+<span class="term">&lt;a id="home"&gt;&lt;/a&gt;&lt;input id="prefix_home" /&gt;&lt;label for="home"&gt;&lt;/label&gt;</span>.<br />
+<br />
+&#160; * &#160;Even if intended HTML is lost from an ill-written input, the processed output will be more secure and standard-compliant.<br />
+<br />
+&#160; * &#160;For URLs, unless <span class="term">$config["scheme"]</span>&#160;is appropriately set, writers should avoid using escape characters or entities in schemes. E.g., <span class="term">htt&amp;#112;</span>&#160;(which many browsers will read as the harmless <span class="term">http</span>) may be considered bad by htmLawed.<br />
+<br />
+&#160; * &#160;htmLawed will attempt to put plain text present directly inside <span class="term">blockquote</span>, <span class="term">form</span>, <span class="term">map</span>&#160;and <span class="term">noscript</span>&#160;elements (illegal as per the specifications) inside auto-generated <span class="term">div</span>&#160;elements during tag balancing (<a href="#s3.3.3">section 3.3.3</a>).<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.8" id="s2.8"></a><span class="item-no">2.8</span>&#160; Limitations &amp; work-arounds
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed's main objective is to make the input text <em>more</em>&#160;standard-compliant, secure for readers, and free of HTML elements and attributes considered undesirable by the administrator. Some of its current limitations, regardless of this objective, are noted below along with possible work-arounds.<br />
+<br />
+&#160; It should be borne in mind that no browser application is 100% standard-compliant, standard specifications continue to evolve, and many browsers accept commonly used non-standard HTML. Regarding security, note that <em>unsafe</em>&#160;HTML code is not legally invalid per se.<br />
+<br />
+&#160; * &#160;By default, htmLawed will not strictly adhere to the <em>current</em>&#160;HTML standard. Admins can configure htmLawed to be more strict about standard compliance. Standard specification for HTML is continuously evolving. There are two bodies (<a href="http://www.w3c.org">W3C</a>&#160;and <a href="http://www.whatwg.org">WHATWG</a>) that specify the standard and their specifications are not identical. E.g., as in mid-2013, the <span class="term">border</span>&#160;attribute is valid in <span class="term">table</span>&#160;as per W3C but not WHATWG. Thus, htmLawed may not be fully compliant with the standard of a specific group. The HTML standards/rules that htmLawed uses in its logic are a mix of the W3C and WHATWG standards, and can be lax because of the laxity of HTML interpreters (browsers) regarding standards.<br />
+<br />
+&#160; * &#160;In general, htmLawed processes input to generate output that is most likely to be standard-compatible in most users' browsers. Thus, for example, it does not enforce the required value of <span class="term">0</span>&#160;on <span class="term">border</span>&#160;attribute of <span class="term">img</span>&#160;(an HTML version 5 specification).<br />
+<br />
+&#160; * &#160;htmLawed is meant for input that goes into the <span class="term">body</span>&#160;of HTML documents. HTML's head-level elements are not supported, nor are the frame-specific elements <span class="term">frameset</span>, <span class="term">frame</span>&#160;and <span class="term">noframes</span>. However, content of the latter elements can be individually filtered through htmLawed.<br />
+<br />
+&#160; * &#160;It cannot handle input that has non-HTML code like <span class="term">SVG</span>&#160;and <span class="term">MathML</span>. One way around is to break the input into pieces and passing only those without non-HTML code to htmLawed. Another is described in <a href="#s3.9">section 3.9</a>. A third way may be to some how take advantage of the <span class="term">$config["and_mark"]</span>&#160;parameter (see <a href="#s3.2">section 3.2</a>).<br />
+<br />
+&#160; * &#160;By default, htmLawed won't check many attribute values for standard compliance. E.g., <span class="term">width="20m"</span>&#160;with the dimension in non-standard <span class="term">m</span>&#160;is let through. Implementing universal and strict attribute value checks can make htmLawed slow and resource-intensive. Admins should look at the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) or <span class="term">$spec</span>&#160;to enforce finer checks on attribute values.<br />
+<br />
+&#160; * &#160;By default, htmLawed considers all ARIA, data-*, event and microdata attributes as global attributes and permits them in all elements. This is not strictly standard-compliant. E.g., the <span class="term">itemtype</span>&#160;microdata attribute is permitted only in elements that also have the <span class="term">itemscope</span>&#160;attribute. Admins can configure htmLawed to be more strict about this (<a href="#s2.3">section 2.3</a>).<br />
+<br />
+&#160; * &#160;The attributes, deprecated (which can be transformed too) or not, that it supports are largely those that are in the specifications. Only a few of the proprietary attributes are supported. However, <span class="term">$spec</span>&#160;can be used to allow custom attributes (<a href="#s2.3">section 2.3</a>).<br />
+<br />
+&#160; * &#160;Except for contained URLs and dynamic expressions (also optional), htmLawed does not check CSS style property values. Admins should look at using the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) or <span class="term">$spec</span>&#160;for finer checks. Perhaps the best option is to disallow <span class="term">style</span>&#160;but allow <span class="term">class</span>&#160;attributes with the right <span class="term">oneof</span>&#160;or <span class="term">match</span>&#160;values for <span class="term">class</span>, and have the various class style properties in <span class="term">.css</span>&#160;CSS stylesheet files.<br />
+<br />
+&#160; * &#160;htmLawed does not parse emoticons, decode <em>BBcode</em>, or <em>wikify</em>, auto-converting text to proper HTML. Similarly, it won't convert line-breaks to <span class="term">br</span>&#160;elements. Such functions are beyond its purview. Admins should use other code to pre- or post-process the input for such purposes.<br />
+<br />
+&#160; * &#160;htmLawed cannot be used to have links force-opened in new windows (by auto-adding appropriate <span class="term">target</span>&#160;and <span class="term">onclick</span>&#160;attributes to <span class="term">a</span>). Admins should look at Javascript-based DOM-modifying solutions for this. Admins may also be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;Nesting-based checks are not possible. E.g., one cannot disallow <span class="term">p</span>&#160;elements specifically inside <span class="term">td</span>&#160;while permitting it elsewhere. Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;Except for optionally converting absolute or relative URLs to the other type, htmLawed will not alter URLs (e.g., to change the value of query strings or to convert <span class="term">http</span>&#160;to <span class="term">https</span>. Having absolute URLs may be a standard-requirement, e.g., when HTML is embedded in email messages, whereas altering URLs for other purposes is beyond htmLawed's goals. Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;Pairs of opening and closing tags that do not enclose any content (like <span class="term">&lt;em&gt;&lt;/em&gt;</span>) are not removed. This may be against the standard specification for certain elements (e.g., <span class="term">table</span>). However, presence of such standard-incompliant code will not break the display or layout of content. Admins can also use simple regex-based code to filter out such code.<br />
+<br />
+&#160; * &#160;htmLawed does not check for certain element orderings described in the standard specifications (e.g., in a <span class="term">table</span>, <span class="term">tbody</span>&#160;is allowed before <span class="term">tfoot</span>). Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;htmLawed does not check the number of nested elements. E.g., it will allow two <span class="term">caption</span>&#160;elements in a <span class="term">table</span>&#160;element, illegal as per standard specifications. Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;There are multiple ways to interpret ill-written HTML. E.g., in <span class="term">&lt;small&gt;&lt;small&gt;text&lt;/small&gt;</span>, is it that the second closing tag for <span class="term">small</span>&#160;is missing or is it that the second opening tag for <span class="term">small</span>&#160;was put in by mistake? htmLawed corrects the HTML in the string assuming the former, while the user may have intended the string for the latter. This is an issue that is impossible to address perfectly.<br />
+<br />
+&#160; * &#160;htmLawed might convert certain entities to actual characters and remove backslashes and CSS comment-markers (<span class="term">/&#42;</span>) in <span class="term">style</span>&#160;attribute values in order to detect malicious HTML like crafted, Internet Explorer browser-specific dynamic expressions like <span class="term">&amp;#101;xpression...</span>. If this is too harsh, admins can allow CSS expressions through htmLawed core but then use a custom function through the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) to more specifically identify CSS expressions in the <span class="term">style</span>&#160;attribute values. Also, using <span class="term">$config["style_pass"]</span>, it is possible to have htmLawed pass <span class="term">style</span>&#160;attribute values without even looking at them (<a href="#s3.4.8">section 3.4.8</a>).<br />
+<br />
+&#160; * &#160;htmLawed does not correct certain possible attribute-based security vulnerabilities (e.g., <span class="term">&lt;a href="http&#58;//x%22+style=%22background-image&#58;xss"&gt;x&lt;/a&gt;</span>). These arise when browsers mis-identify markup in <em>escaped</em>&#160;text, defeating the very purpose of escaping text (a bad browser will read the given example as <span class="term">&lt;a href="http&#58;//x" style="background-image&#58;xss"&gt;x&lt;/a&gt;</span>).<br />
+<br />
+&#160; * &#160;Because of poor Unicode support in PHP, htmLawed does not remove the <em>high value</em>&#160;HTML-invalid characters with multi-byte code-points. Such characters however are extremely unlikely to be in the input. (see <a href="#s3.1">section 3.1</a>).<br />
+<br />
+&#160; * &#160;htmLawed does not check or correct the character encoding of the input it receives. In conjunction with permitting circumstances such as when the character encoding is left undefined through HTTP headers or HTML <span class="term">meta</span>&#160;tags, this can permit an exploit (like Google's <em>UTF-7/XSS</em>&#160;vulnerability of the past). Also, htmLawed can mangle input text if it is not well-formed in terms of character encoding. Administrators can consider using code available elsewhere to check well-formedness of input text characters to correct any defect.<br />
+<br />
+&#160; * &#160;htmLawed is expected to work with input texts in ASCII standard-compatible single-byte encodings such as national variants of ASCII (like ISO-646-DE/German of the ISO 646 standard), extended ASCII variants (like ISO 8859-10/Turkish of the ISO 8859/ISO Latin standard), ISO 8859-based Windows variants (like Windows 1252), EBCDIC, Shift JIS (Japanese), GB-Roman (Chinese), and KS-Roman (Korean). It should also properly handle texts with variable-byte encodings like UTF-7 (Unicode) and UTF-8 (Unicode). However, htmLawed may mangle input texts with double-byte encodings like UTF-16 (Unicode), JIS X 0208:1997 (Japanese) and K SX 1001:1992 (Korean), or the UTF-32 (Unicode) quadruple-byte encoding. If an input text has such an encoding, administrators can use PHP's <a href="http://php.net/manual/en/book.iconv.php">iconv</a>&#160;functions, or some other mean, to convert text to UTF-8 before passing it to htmLawed.<br />
+<br />
+&#160; * &#160;Like any script using PHP's PCRE regex functions, PHP setup-specific low PCRE limit values can cause htmLawed to at least partially fail with very long input texts.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.9" id="s2.9"></a><span class="item-no">2.9</span>&#160; Examples of usage
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Safest, allowing only <em>safe</em>&#160;HTML markup --<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;safe&#39;=&gt;1);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Simplest, allowing all valid HTML markup including Javascript --<br />
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in);</code>
+<br />
+<br />
+&#160; Allowing all valid HTML markup but restricting URL schemes in <span class="term">src</span>&#160;attribute values to <span class="term">http</span>&#160;and <span class="term">https</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;schemes&#39;=&gt;&#39;&#42;&#58;&#42;; src&#58;http, https&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Allowing only <span class="term">safe</span>&#160;HTML and the elements <span class="term">a</span>, <span class="term">em</span>, and <span class="term">strong</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;safe&#39;=&gt;1, &#39;elements&#39;=&gt;&#39;a, em, strong&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Not allowing elements <span class="term">script</span>&#160;and <span class="term">object</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;elements&#39;=&gt;&#39;&#42; -script -object&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Not allowing attributes <span class="term">id</span>&#160;and <span class="term">style</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;deny_attribute&#39;=&gt;&#39;id, style&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Permitting only attributes <span class="term">title</span>&#160;and <span class="term">href</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;deny_attribute&#39;=&gt;&#39;&#42; -title -href&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Remove bad/disallowed tags altogether instead of converting them to entities --<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;keep_bad&#39;=&gt;0);</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config);</code>
+<br />
+<br />
+&#160; Allowing attribute <span class="term">title</span>&#160;only in <span class="term">a</span>&#160;and not allowing attributes <span class="term">id</span>, <span class="term">style</span>, or scriptable <em>on*</em>&#160;attributes like <span class="term">onclick</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;deny_attribute&#39;=&gt;&#39;title, id, style, on&#42;&#39;);</code>
+<br />
+
+<code class="code">&#160; &#160; $spec = &#39;a=title&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config, $spec);</code>
+<br />
+<br />
+&#160; Allowing a custom attribute, <span class="term">vFlag</span>, in <span class="term">img</span>&#160;and permitting custom use of the standard attribute, <span class="term">rel</span>, in <span class="term">input</span>&#160;--<br />
+<br />
+
+<code class="code">&#160; &#160; $spec = &#39;img=vFlag; input=rel&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; $out = htmLawed($in, $config, $spec);</code>
+<br />
+<br />
+&#160; Some case-studies are presented below.<br />
+<br />
+&#160; <strong>1.</strong>&#160;A blog administrator wants to allow only <span class="term">a</span>, <span class="term">em</span>, <span class="term">strike</span>, <span class="term">strong</span>&#160;and <span class="term">u</span>&#160;in comments, but needs <span class="term">strike</span>&#160;and <span class="term">u</span>&#160;transformed to <span class="term">span</span>&#160;for better XHTML 1-strict compliance, and, he wants the <span class="term">a</span>&#160;links to point only to <span class="term">http</span>&#160;or <span class="term">https</span>&#160;resources:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($in, array(&#39;elements&#39;=&gt;&#39;a, em, strike, strong, u&#39;, &#39;make_tag_strict&#39;=&gt;1, &#39;safe&#39;=&gt;1, &#39;schemes&#39;=&gt;&#39;&#42;&#58;http, https&#39;), &#39;a=href&#39;);</code>
+<br />
+<br />
+&#160; <strong>2.</strong>&#160;An author uses a custom-made web application to load content on his website. He is the only one using that application and the content he generates has all types of HTML, including scripts. The web application uses htmLawed primarily as a tool to correct errors that creep in while writing HTML and to take care of the occasional <em>bad</em>&#160;characters in copy-paste text introduced by Microsoft Office. The web application provides a preview before submitted input is added to the content. For the previewing process, htmLawed is set up as follows:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($in, array(&#39;css_expression&#39;=&gt;1, &#39;keep_bad&#39;=&gt;1, &#39;make_tag_strict&#39;=&gt;1, &#39;schemes&#39;=&gt;&#39;&#42;&#58;&#42;&#39;, &#39;valid_xhtml&#39;=&gt;1));</code>
+<br />
+<br />
+&#160; For the final submission process, <span class="term">keep_bad</span>&#160;is set to <span class="term">6</span>. A value of <span class="term">1</span>&#160;for the preview process allows the author to note and correct any HTML mistake without losing any of the typed text.<br />
+<br />
+&#160; <strong>3.</strong>&#160;A data-miner is scraping information in a specific table of similar web-pages and is collating the data rows, and uses htmLawed to reduce unnecessary markup and white-spaces:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($in, array(&#39;elements&#39;=&gt;&#39;tr, td&#39;, &#39;tidy&#39;=&gt;-1), &#39;tr, td =&#39;);</code>
+<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s3" id="s3"></a><span class="item-no">3</span>&#160; Details
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<div class="sub-section"><h3>
+<a name="s3.1" id="s3.1"></a><span class="item-no">3.1</span>&#160; Invalid/dangerous characters
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Valid characters (more correctly, their code-points) in HTML or XML are, hexadecimally, <span class="term">9</span>, <span class="term">a</span>, <span class="term">d</span>, <span class="term">20</span>&#160;to <span class="term">d7ff</span>, and <span class="term">e000</span>&#160;to <span class="term">10ffff</span>, except <span class="term">fffe</span>&#160;and <span class="term">ffff</span>&#160;(decimally, <span class="term">9</span>, <span class="term">10</span>, <span class="term">13</span>, <span class="term">32</span>&#160;to <span class="term">55295</span>, and <span class="term">57344</span>&#160;to <span class="term">1114111</span>, except <span class="term">65534</span>&#160;and <span class="term">65535</span>). htmLawed removes the invalid characters <span class="term">0</span>&#160;to <span class="term">8</span>, <span class="term">b</span>, <span class="term">c</span>, and <span class="term">e</span>&#160;to <span class="term">1f</span>.<br />
+<br />
+&#160; Because of PHP's poor native support for multi-byte characters, htmLawed cannot check for the remaining invalid code-points. However, for various reasons, it is very unlikely for any of those characters to be in the input.<br />
+<br />
+&#160; Characters that are discouraged (see <a href="#s5.1">section 5.1</a>) but not invalid are not removed by htmLawed.<br />
+<br />
+&#160; It (function <span class="term">hl_tag()</span>) also replaces the potentially dangerous (in some Mozilla [Firefox] and Opera browsers) soft-hyphen character (code-point, hexadecimally, <span class="term">ad</span>, or decimally, <span class="term">173</span>) in attribute values with spaces. Where required, the characters <span class="term">&lt;</span>, <span class="term">&gt;</span>, <span class="term">&amp;</span>, and <span class="term">"</span>&#160;are converted to entities.<br />
+<br />
+&#160; With <span class="term">$config["clean_ms_char"]</span>&#160;set as <span class="term">1</span>&#160;or <span class="term">2</span>, many of the discouraged characters (decimal code-points <span class="term">127</span>&#160;to <span class="term">159</span>&#160;except <span class="term">133</span>) that many Microsoft applications incorrectly use (as per the <span class="term">Windows 1252</span>&#160;[<span class="term">Cp-1252</span>] or a similar encoding system), and the character for decimal code-point <span class="term">133</span>, are converted to appropriate decimal numerical entities (or removed for a few cases)-- see appendix in <a href="#s5.4">section 5.4</a>. This can help avoid some display issues arising from copying-pasting of content.<br />
+<br />
+&#160; With <span class="term">$config["clean_ms_char"]</span>&#160;set as <span class="term">2</span>, characters for the hexadecimal code-points <span class="term">82</span>, <span class="term">91</span>, and <span class="term">92</span>&#160;(for special single-quotes), and <span class="term">84</span>, <span class="term">93</span>, and <span class="term">94</span>&#160;(for special double-quotes) are converted to ordinary single and double quotes respectively and not to entities.<br />
+<br />
+&#160; The character values are replaced with entities/characters and not character values referred to by the entities/characters to keep this task independent of the character-encoding of input text.<br />
+<br />
+&#160; The <span class="term">$config["clean_ms_char"]</span>&#160;parameter should not be used if authors do not copy-paste Microsoft-created text, or if the input text is not believed to use the <span class="term">Windows 1252</span>&#160;(<span class="term">Cp-1252</span>) or a similar encoding like <span class="term">Cp-1251</span>&#160;(otherwise, for example when UTF-8 encoding is in use, Japanese or Korean characters can get mangled). Further, the input form and the web-pages displaying it or its content should have the character encoding appropriately marked-up.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.2" id="s3.2"></a><span class="item-no">3.2</span>&#160; Character references/entities
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Valid character entities take the form <span class="term">&amp;&#42;;</span>&#160;where <span class="term">&#42;</span>&#160;is <span class="term">#x</span>&#160;followed by a hexadecimal number (hexadecimal numeric entity; like <span class="term">&amp;#xA0;</span>&#160;for non-breaking space), or alphanumeric like <span class="term">gt</span>&#160;(external or named entity; like <span class="term">&amp;nbsp;</span>&#160;for non-breaking space), or <span class="term">#</span>&#160;followed by a number (decimal numeric entity; like <span class="term">&amp;#160;</span>&#160;for non-breaking space). Character entities referring to the soft-hyphen character (the <span class="term">&amp;shy;</span>&#160;or <span class="term">\xad</span>&#160;character; hexadecimal code-point <span class="term">ad</span>&#160;[decimal <span class="term">173</span>]) in URL-accepting attribute values are always replaced with spaces; soft-hyphens in attribute values introduce vulnerabilities in some older versions of the Opera and Mozilla [Firefox] browsers.<br />
+<br />
+&#160; htmLawed (function <span class="term">hl_ent()</span>):<br />
+<br />
+&#160; * &#160;Neutralizes entities with multiple leading zeroes or missing semi-colons (potentially dangerous)<br />
+<br />
+&#160; * &#160;Lowercases the <span class="term">X</span>&#160;(for XML-compliance) and <span class="term">A-F</span>&#160;of hexadecimal numeric entities<br />
+<br />
+&#160; * &#160;Neutralizes entities referring to characters that are HTML-invalid (see <a href="#s3.1">section 3.1</a>)<br />
+<br />
+&#160; * &#160;Neutralizes entities referring to characters that are HTML-discouraged (code-points, hexadecimally, <span class="term">7f</span>&#160;to <span class="term">84</span>, <span class="term">86</span>&#160;to <span class="term">9f</span>, and <span class="term">fdd0</span>&#160;to <span class="term">fddf</span>, or decimally, <span class="term">127</span>&#160;to <span class="term">132</span>, <span class="term">134</span>&#160;to <span class="term">159</span>, and <span class="term">64991</span>&#160;to <span class="term">64976</span>). Entities referring to the remaining discouraged characters (see <a href="#s5.1">section 5.1</a>&#160;for a full list) are let through.<br />
+<br />
+&#160; * &#160;Neutralizes named entities that are not in the specifications<br />
+<br />
+&#160; * &#160;Optionally converts valid HTML-specific named entities except <span class="term">&amp;gt;</span>, <span class="term">&amp;lt;</span>, <span class="term">&amp;quot;</span>, and <span class="term">&amp;amp;</span>&#160;to decimal numeric ones (hexadecimal if $config["hexdec_entity"] is <span class="term">2</span>) for generic XML-compliance. For this, <span class="term">$config["named_entity"]</span>&#160;should be <span class="term">1</span>.<br />
+<br />
+&#160; * &#160;Optionally converts hexadecimal numeric entities to the more widely supported decimal ones. For this, <span class="term">$config["hexdec_entity"]</span>&#160;should be <span class="term">0</span>.<br />
+<br />
+&#160; * &#160;Optionally converts decimal numeric entities to the hexadecimal ones. For this, <span class="term">$config["hexdec_entity"]</span>&#160;should be <span class="term">2</span>.<br />
+<br />
+&#160; <em>Neutralization</em>&#160;refers to the <em>entitification</em>&#160;of <span class="term">&amp;</span>&#160;to <span class="term">&amp;amp;</span>.<br />
+<br />
+&#160; <strong>Note</strong>: htmLawed does not convert entities to the actual characters represented by them; one can pass the htmLawed output through PHP's <span class="term">html_entity_decode</span>&#160;<a href="http://www.php.net/html_entity_decode">function</a>&#160;for that.<br />
+<br />
+&#160; <strong>Note</strong>: If <span class="term">$config["and_mark"]</span>&#160;is set, and set to a value other than <span class="term">0</span>, then the <span class="term">&amp;</span>&#160;characters in the original input are replaced with the control character for the hexadecimal code-point <span class="term">6</span>&#160;(<span class="term">\x06</span>; <span class="term">&amp;</span>&#160;characters introduced by htmLawed, e.g., after converting <span class="term">&lt;</span>&#160;to <span class="term">&amp;lt;</span>, are not affected). This allows one to distinguish, say, an <span class="term">&amp;gt;</span>&#160;introduced by htmLawed and an <span class="term">&amp;gt;</span>&#160;put in by the input writer, and can be helpful in further processing of the htmLawed-processed text (e.g., to identify the character sequence <span class="term">o(&gt;&lt;)o</span>&#160;to generate an emoticon image). When this feature is active, admins should ensure that the htmLawed output is not directly used in web pages or XML documents as the presence of the <span class="term">\x06</span>&#160;can break documents. Before use in such documents, and preferably before any storage, any remaining <span class="term">\x06</span>&#160;should be changed back to <span class="term">&amp;</span>, e.g., with:<br />
+<br />
+
+<code class="code">&#160; &#160; $final = str_replace("\x06", &#39;&amp;&#39;, $prelim);</code>
+<br />
+<br />
+&#160; Also, see <a href="#s3.9">section 3.9</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.3" id="s3.3"></a><span class="item-no">3.3</span>&#160; HTML elements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can be configured to allow only certain HTML elements (tags) in the input. Disallowed elements (just tag-content, and not element-content), based on <span class="term">$config["keep_bad"]</span>, are either <em>neutralized</em>&#160;(converted to plain text by entitification of <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>) or removed.<br />
+<br />
+&#160; E.g., with only <span class="term">em</span>&#160;permitted:<br />
+<br />
+&#160; Input:<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;em&gt;My&lt;/em&gt; website is &lt;a href="http&#58;//a.com&gt;a.com&lt;/a&gt;.</code>
+<br />
+<br />
+&#160; Output, with <span class="term">$config["keep_bad"] = 0</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;em&gt;My&lt;/em&gt; website is a.com.</code>
+<br />
+<br />
+&#160; Output, with <span class="term">$config["keep_bad"]</span>&#160;not <span class="term">0</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;em&gt;My&lt;/em&gt; website is &amp;lt;a href=""&amp;gt;a.com&amp;lt;/a&amp;gt;.</code>
+<br />
+<br />
+&#160; See <a href="#s3.3.3">section 3.3.3</a>&#160;for differences between the various non-zero <span class="term">$config["keep_bad"]</span>&#160;values.<br />
+<br />
+&#160; htmLawed by default permits these 118 HTML elements:<br />
+<br />
+
+<code class="code">&#160; &#160; a, abbr, acronym, address, applet, area, article, aside, audio, b, bdi, bdo, big, blockquote, br, button, canvas, caption, center, cite, code, col, colgroup, command, data, datalist, dd, del, details, dfn, dir, div, dl, dt, em, embed, fieldset, figcaption, figure, font, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, i, iframe, img, input, ins, isindex, kbd, keygen, label, legend, li, link, main, map, mark, menu, meta, meter, nav, noscript, object, ol, optgroup, option, output, p, param, pre, progress, q, rb, rbc, rp, rt, rtc, ruby, s, samp, script, section, select, small, source, span, strike, strong, style, sub, summary, sup, table, tbody, td, textarea, tfoot, th, thead, time, tr, track, tt, u, ul, var, video, wbr</code>
+<br />
+<br />
+&#160; The HTML version 4 elements <span class="term">acronym</span>, <span class="term">applet</span>, <span class="term">big</span>, <span class="term">center</span>, <span class="term">dir</span>, <span class="term">font</span>, <span class="term">strike</span>, and <span class="term">tt</span>&#160;are obsolete/deprecated in HTML version 5. On the other hand, the obsolete/deprecated HTML 4 elements <span class="term">embed</span>, <span class="term">menu</span>&#160;and <span class="term">u</span>&#160;are no longer so in HTML 5. Elements new to HTML 5 are <span class="term">article</span>, <span class="term">aside</span>, <span class="term">audio</span>, <span class="term">bdi</span>, <span class="term">canvas</span>, <span class="term">command</span>, <span class="term">data</span>, <span class="term">datalist</span>, <span class="term">details</span>, <span class="term">figure</span>, <span class="term">figcaption</span>, <span class="term">footer</span>, <span class="term">header</span>, <span class="term">hgroup</span>, <span class="term">keygen</span>, <span class="term">link</span>, <span class="term">main</span>, <span class="term">mark</span>, <span class="term">meta</span>, <span class="term">meter</span>, <span class="term">nav</span>, <span class="term">output</span>, <span class="term">progress</span>, <span class="term">section</span>, <span class="term">source</span>, <span class="term">style</span>, <span class="term">summary</span>, <span class="term">time</span>, <span class="term">track</span>, <span class="term">video</span>, and <span class="term">wbr</span>. The <span class="term">link</span>, <span class="term">meta</span>&#160;and <span class="term">style</span>&#160;elements exist in HTML 4 but are not allowed in the HTML body. These 16 elements are <em>empty</em>&#160;elements that have an opening tag with possible content but no element content (thus, no closing tag): <span class="term">area</span>, <span class="term">br</span>, <span class="term">col</span>, <span class="term">command</span>, <span class="term">embed</span>, <span class="term">hr</span>, <span class="term">img</span>, <span class="term">input</span>, <span class="term">isindex</span>, <span class="term">keygen</span>, <span class="term">link</span>, <span class="term">meta</span>, <span class="term">param</span>, <span class="term">source</span>, <span class="term">track</span>, and <span class="term">wbr</span>.<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>, the default set will exclude <span class="term">applet</span>, <span class="term">audio</span>, <span class="term">canvas</span>, <span class="term">embed</span>, <span class="term">iframe</span>, <span class="term">object</span>, <span class="term">script</span>&#160;and <span class="term">video</span>; see <a href="#s3.6">section 3.6</a>.<br />
+<br />
+&#160; When <span class="term">$config["elements"]</span>, which specifies allowed elements, is <em>properly</em>&#160;defined, and neither empty nor set to <span class="term">0</span>&#160;or <span class="term">&#42;</span>, the default set is not used. To have elements added to or removed from the default set, a <span class="term">+/-</span>&#160;notation is used. E.g., <span class="term">&#42;-script-object</span>&#160;implies that only <span class="term">script</span>&#160;and <span class="term">object</span>&#160;are disallowed, whereas <span class="term">&#42;+embed</span>&#160;means that <span class="term">noembed</span>&#160;is also allowed. Elements can also be specified as comma separated names. E.g., <span class="term">a, b, i</span>&#160;means only <span class="term">a</span>, <span class="term">b</span>&#160;and <span class="term">i</span>&#160;are permitted. In this notation, <span class="term">&#42;</span>, <span class="term">+</span>&#160;and <span class="term">-</span>&#160;have no significance and can actually cause a mis-reading.<br />
+<br />
+&#160; Some more examples of <span class="term">$config["elements"]</span>&#160;values indicating permitted elements (note that empty spaces are liberally allowed for clarity):<br />
+<br />
+&#160; * &#160;<span class="term">a, blockquote, code, em, strong</span>&#160;-- only <span class="term">a</span>, <span class="term">blockquote</span>, <span class="term">code</span>, <span class="term">em</span>, and <span class="term">strong</span><br />
+&#160; * &#160;<span class="term">&#42;-script</span>&#160;-- all excluding <span class="term">script</span><br />
+&#160; * &#160;<span class="term">&#42; -acronym -big -center -dir -font -isindex -s -strike -tt</span>&#160;-- only non-obsolete/deprecated elements of HTML5<br />
+&#160; * &#160;<span class="term">&#42;+noembed-script</span>&#160;-- all including <span class="term">noembed</span>&#160;excluding <span class="term">script</span><br />
+<br />
+&#160; Some mis-usages (and the resulting permitted elements) that can be avoided:<br />
+<br />
+&#160; * &#160;<span class="term">-&#42;</span>&#160;-- none; instead of htmLawed, one might just use, e.g., the <span class="term">htmlspecialchars()</span>&#160;PHP function<br />
+&#160; * &#160;<span class="term">&#42;, -script</span>&#160;-- all except <span class="term">script</span>; admin probably meant <span class="term">&#42;-script</span><br />
+&#160; * &#160;<span class="term">-&#42;, a, em, strong</span>&#160;-- all; admin probably meant <span class="term">a, em, strong</span><br />
+&#160; * &#160;<span class="term">&#42;</span>&#160;-- all; admin need not have set <span class="term">elements</span><br />
+&#160; * &#160;<span class="term">&#42;-form+form</span>&#160;-- all; a <span class="term">+</span>&#160;will always over-ride any <span class="term">-</span><br />
+&#160; * &#160;<span class="term">&#42;, noembed</span>&#160;-- only <span class="term">noembed</span>; admin probably meant <span class="term">&#42;+noembed</span><br />
+&#160; * &#160;<span class="term">a, +b, i</span>&#160;-- only <span class="term">a</span>&#160;and <span class="term">i</span>; admin probably meant <span class="term">a, b, i</span><br />
+<br />
+&#160; Basically, when using the <span class="term">+/-</span>&#160;notation, commas (<span class="term">,</span>) should not be used, and vice versa, and <span class="term">&#42;</span>&#160;should be used with the former but not the latter.<br />
+<br />
+&#160; <strong>Note</strong>: Even if an element that is not in the default set is allowed through <span class="term">$config["elements"]</span>, like <span class="term">noembed</span>&#160;in the last example, it will eventually be removed during tag balancing unless such balancing is turned off (<span class="term">$config["balance"]</span>&#160;set to <span class="term">0</span>). Currently, the only way around this, which actually is simple, is to edit htmLawed's PHP code which define various arrays in the function <span class="term">hl_bal()</span>&#160;to accommodate the element and its nesting properties.<br />
+<br />
+&#160; A possible second way to specify allowed elements is to set <span class="term">$config["parent"]</span>&#160;to an element name that supposedly will hold the input, and to set <span class="term">$config["balance"]</span>&#160;to <span class="term">1</span>. During tag balancing (see <a href="#s3.3.3">section 3.3.3</a>), all elements that cannot legally nest inside the parent element will be removed. The parent element is auto-reset to <span class="term">div</span>&#160;if <span class="term">$config["parent"]</span>&#160;is empty, <span class="term">body</span>, or an element not in htmLawed's default set of 118 elements.<br />
+<br />
+&#160; <em>Tag transformation</em>&#160;is possible for improving compliance with HTML standards -- most of the obsolete/deprecated elements of HTML version 5 are converted to valid &#160;ones; see <a href="#s3.3.2">section 3.3.2</a>.<br />
+
+<div class="sub-sub-section"><h4>
+<a name="s3.3.1" id="s3.3.1"></a><span class="item-no">3.3.1</span>&#160; Handling of comments &amp; CDATA sections
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <span class="term">CDATA</span>&#160;sections have the format <span class="term">&lt;![CDATA[...anything but not "]]&gt;"...]]&gt;</span>, and HTML comments, <span class="term">&lt;!--...anything but not "--&gt;"... --&gt;</span>. Neither HTML comments nor <span class="term">CDATA</span>&#160;sections can reside inside tags. HTML comments can exist anywhere else, but <span class="term">CDATA</span>&#160;sections can exist only where plain text is allowed (e.g., immediately inside <span class="term">td</span>&#160;element content but not immediately inside <span class="term">tr</span>&#160;element content).<br />
+<br />
+&#160; htmLawed (function <span class="term">hl_cmtcd()</span>) handles HTML comments or <span class="term">CDATA</span>&#160;sections depending on the values of <span class="term">$config["comment"]</span>&#160;or <span class="term">$config["cdata"]</span>. If <span class="term">0</span>, such markup is not looked for and the text is processed like plain text. If <span class="term">1</span>, it is removed completely. If <span class="term">2</span>, it is preserved but any <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;inside are changed to entities. If <span class="term">3</span>&#160;for <span class="term">$config["cdata"]</span>, or <span class="term">3</span>&#160;or <span class="term">4</span>&#160;for <span class="term">$config["comment"]</span>, they are left as such. When <span class="term">$config["comment"]</span>&#160;is set to <span class="term">4</span>, htmLawed will not force a space character before the <span class="term">--&gt;</span>&#160;comment-closing marker. While such a space is required for standard-compliance, it can corrupt marker code put in HTML by some software (such as Microsoft Outlook).<br />
+<br />
+&#160; Note that for the last two cases, HTML comments and <span class="term">CDATA</span>&#160;sections will always be removed from tag content (function <span class="term">hl_tag()</span>).<br />
+<br />
+&#160; Examples:<br />
+<br />
+&#160; Input:<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link--&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 0, $config["cdata"] = 2</span>):<br />
+
+<code class="code">&#160; &#160; &amp;lt;-- home link--&amp;gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 1, $config["cdata"] = 2</span>):<br />
+
+<code class="code">&#160; &#160; &lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 2, $config["cdata"] = 2</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 2, $config["cdata"] = 1</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 3, $config["cdata"] = 3</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 4, $config["cdata"] = 3</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link--&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+<br />
+&#160; For standard-compliance, comments are given the form <span class="term">&lt;!--comment --&gt;</span>, and any <span class="term">--</span>&#160;in the content is made <span class="term">-</span>. When <span class="term">$config["comment"]</span>&#160;is set to <span class="term">4</span>, htmLawed will not force a space character before the <span class="term">--&gt;</span>&#160;comment-closing marker.<br />
+<br />
+&#160; When <span class="term">$config["safe"] = 1</span>, CDATA sections and comments are considered plain text unless <span class="term">$config["comment"]</span>&#160;or <span class="term">$config["cdata"]</span>&#160;is explicitly specified; see <a href="#s3.6">section 3.6</a>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.3.2" id="s3.3.2"></a><span class="item-no">3.3.2</span>&#160; Tag-transformation for better compliance with standards
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["make_tag_strict"]</span>&#160;is set and not <span class="term">0</span>, following deprecated elements (and attributes), as per HTML 5 specification, even if admin-permitted, are mutated as indicated (element content remains intact; function <span class="term">hl_tag2()</span>):<br />
+<br />
+&#160; * &#160;acronym - <span class="term">abbr</span><br />
+&#160; * &#160;applet - based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>)<br />
+&#160; * &#160;big - <span class="term">span style="font-size&#58; larger;"</span><br />
+&#160; * &#160;center - <span class="term">div style="text-align&#58; center;"</span><br />
+&#160; * &#160;dir - <span class="term">ul</span><br />
+&#160; * &#160;font (face, size, color) - &#160; &#160;<span class="term">span style="font-family&#58; ; font-size&#58; ; color&#58; ;"</span>&#160;(size transformation <a href="http://web.archive.org/web/20180201141931/http://style.cleverchimp.com/font_size_intervals/altintervals.html">reference</a>)<br />
+&#160; * &#160;isindex - based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>)<br />
+&#160; * &#160;s - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
+&#160; * &#160;strike - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
+&#160; * &#160;tt - <span class="term">code</span><br />
+<br />
+&#160; For an element with a pre-existing <span class="term">style</span>&#160;attribute value, the extra style properties are appended.<br />
+<br />
+&#160; Example input:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;center&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;The PHP &lt;s&gt;software&lt;/s&gt; script used for this &lt;strike&gt;web-page&lt;/strike&gt; web-page is &lt;font style="font-weight&#58; bold " face=arial size=&#39;+3&#39; color &#160; = &#160;"red &#160;"&gt;htmLawedTest.php&lt;/font&gt;, from &lt;u style= &#39;color&#58;green&#39;&gt;PHP Labware&lt;/u&gt;.</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/center&gt;</code>
+<br />
+<br />
+&#160; The output:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;div style="text-align&#58; center;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;The PHP &lt;span style="text-decoration&#58; line-through;"&gt;software&lt;/span&gt; script used for this &lt;span style="text-decoration&#58; line-through;"&gt;web-page&lt;/span&gt; web-page is &lt;span style="font-weight&#58; bold; font-size&#58; 200%; color&#58; red; font-family&#58; arial;"&gt;htmLawedTest.php&lt;/span&gt;, from &lt;u style="color&#58;green"&gt;PHP Labware&lt;/u&gt;.</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/div&gt;</code>
+<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.3.3" id="s3.3.3"></a><span class="item-no">3.3.3</span>&#160; Tag balancing &amp; proper nesting
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["balance"]</span>&#160;is set to <span class="term">1</span>, htmLawed (function <span class="term">hl_bal()</span>) checks and corrects the input to have properly balanced tags and legal element content (i.e., any element nesting should be valid, and plain text may be present only in the content of elements that allow them).<br />
+<br />
+&#160; Depending on the value of <span class="term">$config["keep_bad"]</span>&#160;(see <a href="#s2.2">section 2.2</a>&#160;and <a href="#s3.3">section 3.3</a>), illegal content may be removed or neutralized to plain text by converting &lt; and &gt; to entities:<br />
+<br />
+&#160; <span class="term">0</span>&#160;- remove; this option is available only to maintain Kses-compatibility and should not be used otherwise (see <a href="#s2.6">section 2.6</a>)<br />
+&#160; <span class="term">1</span>&#160;- neutralize tags and keep element content<br />
+&#160; <span class="term">2</span>&#160;- remove tags but keep element content<br />
+&#160; <span class="term">3</span>&#160;and <span class="term">4</span>&#160;- like <span class="term">1</span>&#160;and <span class="term">2</span>, but keep element content only if text (<span class="term">pcdata</span>) is valid in parent element as per specs<br />
+&#160; <span class="term">5</span>&#160;and <span class="term">6</span>&#160;- &#160;like <span class="term">3</span>&#160;and <span class="term">4</span>, but line-breaks, tabs and spaces are left<br />
+<br />
+&#160; Example input (disallowing the <span class="term">p</span>&#160;element):<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;&#42;&gt; Pseudo-tags &lt;&#42;&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;xml&gt;Non-HTML tag xml&lt;/xml&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;Bad&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; The output with <span class="term">$config["keep_bad"] = 1</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;&#42;&amp;gt; Pseudo-tags &amp;lt;&#42;&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;xml&amp;gt;Non-HTML tag xml&amp;lt;/xml&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;/p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;Bad&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; The output with <span class="term">$config["keep_bad"] = 3</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;&#42;&amp;gt; Pseudo-tags &amp;lt;&#42;&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;xml&amp;gt;Non-HTML tag xml&amp;lt;/xml&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;/p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; The output with <span class="term">$config["keep_bad"] = 6</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;&#42;&amp;gt; Pseudo-tags &amp;lt;&#42;&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Non-HTML tag xml</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; An option like <span class="term">1</span>&#160;is useful, e.g., when a writer previews his submission, whereas one like <span class="term">3</span>&#160;is useful before content is finalized and made available to all.<br />
+<br />
+&#160; <strong>Note:</strong>&#160;In the example above, unlike <span class="term">&lt;&#42;&gt;</span>, <span class="term">&lt;xml&gt;</span>&#160;gets considered as a tag (even though there is no HTML element named <span class="term">xml</span>). Thus, the <span class="term">keep_bad</span>&#160;parameter's value affects <span class="term">&lt;xml&gt;</span>&#160;but not <span class="term">&lt;&#42;&gt;</span>. In general, text matching the regular expression pattern <span class="term">&lt;(/?)([a-zA-Z][a-zA-Z1-6]&#42;)([^&gt;]&#42;?)\s?&gt;</span>&#160;is considered a tag (phrase enclosed by the angled brackets <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>, and starting [with an optional slash preceding] with an alphanumeric word that starts with an alphabet...), and is subjected to the <span class="term">keep_bad</span>&#160;value.<br />
+<br />
+&#160; Nesting/content rules for each of the 118 elements in htmLawed's default set (see <a href="#s3.3">section 3.3</a>) are defined in function <span class="term">hl_bal()</span>. This means that if a non-standard element besides <span class="term">embed</span>&#160;is being permitted through <span class="term">$config["elements"]</span>, the element's tag content will end up getting removed if <span class="term">$config["balance"]</span>&#160;is set to <span class="term">1</span>.<br />
+<br />
+&#160; Plain text and/or certain elements nested inside <span class="term">blockquote</span>, <span class="term">form</span>, <span class="term">map</span>&#160;and <span class="term">noscript</span>&#160;need to be in block-level elements. This point is often missed during manual writing of HTML code. htmLawed attempts to address this during balancing. E.g., if the parent container is set as <span class="term">form</span>, the input <span class="term">B&#58;&lt;input type="text" value="b" /&gt;C&#58;&lt;input type="text" value="c" /&gt;</span>&#160;is converted to <span class="term">&lt;div&gt;B&#58;&lt;input type="text" value="b" /&gt;C&#58;&lt;input type="text" value="c" /&gt;&lt;/div&gt;</span>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.3.4" id="s3.3.4"></a><span class="item-no">3.3.4</span>&#160; Elements requiring child elements
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; As per HTML specifications, elements such as those below require legal child elements nested inside them:<br />
+<br />
+
+<code class="code">&#160; &#160; blockquote, dir, dl, form, map, menu, noscript, ol, optgroup, rbc, rtc, ruby, select, table, tbody, tfoot, thead, tr, ul</code>
+<br />
+<br />
+&#160; In some cases, the specifications stipulate the number and/or the ordering of the child elements. A <span class="term">table</span>&#160;can have 0 or 1 <span class="term">caption</span>, <span class="term">tbody</span>, <span class="term">tfoot</span>, and <span class="term">thead</span>, but they must be in this order: <span class="term">caption</span>, <span class="term">thead</span>, <span class="term">tfoot</span>, <span class="term">tbody</span>.<br />
+<br />
+&#160; htmLawed currently does not check for conformance to these rules. Note that any non-compliance in this regard will not introduce security vulnerabilities, crash browser applications, or affect the rendering of web-pages.<br />
+<br />
+&#160; With <span class="term">$config["direct_list_nest"]</span>&#160;set to <span class="term">1</span>, htmLawed will allow direct nesting of <span class="term">ol</span>, <span class="term">ul</span>, or <span class="term">menu</span>&#160;list within another <span class="term">ol</span>, <span class="term">ul</span>, or <span class="term">menu</span>&#160;without requiring the child list to be within an <span class="term">li</span>&#160;of the parent list. While this may not be standard-compliant, directly nested lists are rendered properly by almost all browsers. The parameter <span class="term">$config["direct_list_nest"]</span>&#160;has no effect if tag balancing (<a href="#s3.3.3">section 3.3.3</a>) is turned off.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.3.5" id="s3.3.5"></a><span class="item-no">3.3.5</span>&#160; Beautify or compact HTML
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; By default, htmLawed will neither <em>beautify</em>&#160;HTML code by formatting it with indentations, etc., nor will it make it compact by removing un-needed white-space.(It does always properly white-space tag content.)<br />
+<br />
+&#160; As per the HTML standards, spaces, tabs and line-breaks in web-pages (except those inside <span class="term">pre</span>&#160;elements) are all considered equivalent, and referred to as <em>white-spaces</em>. Browser applications are supposed to consider contiguous white-spaces as just a single space, and to disregard white-spaces trailing opening tags or preceding closing tags. This white-space <em>normalization</em>&#160;allows the use of text/code beautifully formatted with indentations and line-spacings for readability. Such <em>pretty</em>&#160;HTML can, however, increase the size of web-pages, or make the extraction or scraping of plain text cumbersome.<br />
+<br />
+&#160; With the <span class="term">$config</span>&#160;parameter <span class="term">tidy</span>, htmLawed can be used to beautify or compact the input text. Input with just plain text and no HTML markup is also subject to this. Besides <span class="term">pre</span>, the <span class="term">script</span>&#160;and <span class="term">textarea</span>&#160;elements, CDATA sections, and HTML comments are not subjected to the tidying process.<br />
+<br />
+&#160; To <em>compact</em>, use <span class="term">$config["tidy"] = -1</span>; single instances or runs of white-spaces are replaced with a single space, and white-spaces trailing and leading open and closing tags, respectively, are removed.<br />
+<br />
+&#160; To <em>beautify</em>, <span class="term">$config["tidy"]</span>&#160;is set as <span class="term">1</span>, or for customized tidying, as a string like <span class="term">2s2n</span>. The <span class="term">s</span>&#160;or <span class="term">t</span>&#160;character specifies the use of spaces or tabs for indentation. The first and third characters, any of the digits 0-9, specify the number of spaces or tabs per indentation, and any parental lead spacing (extra indenting of the whole block of input text). The <span class="term">r</span>&#160;and <span class="term">n</span>&#160;characters are used to specify line-break characters: <span class="term">n</span>&#160;for <span class="term">\n</span>&#160;(Unix/Mac OS X line-breaks), <span class="term">rn</span>&#160;or <span class="term">nr</span>&#160;for <span class="term">\r\n</span>&#160;(Windows/DOS line-breaks), or <span class="term">r</span>&#160;for <span class="term">\r</span>.<br />
+<br />
+&#160; The <span class="term">$config["tidy"]</span>&#160;value of <span class="term">1</span>&#160;is equivalent to <span class="term">2s0n</span>. Other <span class="term">$config["tidy"]</span>&#160;values are read loosely: a value of <span class="term">4</span>&#160;is equivalent to <span class="term">4s0n</span>; <span class="term">t2</span>, to <span class="term">1t2n</span>; <span class="term">s</span>, to <span class="term">2s0n</span>; <span class="term">2TR</span>, to <span class="term">2t0r</span>; <span class="term">T1</span>, to <span class="term">1t1n</span>; <span class="term">nr3</span>, to <span class="term">3s0nr</span>, and so on. Except in the indentations and line-spacings, runs of white-spaces are replaced with a single space during beautification.<br />
+<br />
+&#160; Input formatting using <span class="term">$config["tidy"]</span>&#160;is not recommended when input text has mixed markup (like HTML + PHP).<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.4" id="s3.4"></a><span class="item-no">3.4</span>&#160; Attributes
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; In its default setting, htmLawed will only permit attributes described in the HTML specifications (including deprecated ones). A list of the attributes and the elements they are allowed in is in <a href="#s5.2">section 5.2</a>. Using the <span class="term">$spec</span>&#160;argument, htmLawed can be forced to permit custom, non-standard attributes as well as custom rules for standard attributes (<a href="#s2.3">section 2.3</a>).<br />
+<br />
+&#160; Custom <em>data-*</em>&#160;(<em>data-star</em>) attributes, where the first three characters of the value of <em>star</em>&#160;(*) after lower-casing do not equal <span class="term">xml</span>, and the value of <em>star</em>&#160;does not have a colon (:), equal-to (=), newline, solidus (/), space or tab character, or any upper-case A-Z character are allowed in all elements. ARIA, event and microdata attributes like <span class="term">aria-live</span>, <span class="term">onclick</span>&#160;and <span class="term">itemid</span>&#160;are also considered global attributes (<a href="#s5.2">section 5.2</a>).<br />
+<br />
+&#160; When <span class="term">$config["deny_attribute"]</span>&#160;is not set, or set to <span class="term">0</span>, or empty (<span class="term">""</span>), all attributes are permitted. Otherwise, <span class="term">$config["deny_attribute"]</span>&#160;can be set as a list of comma-separated names of the denied attributes. <span class="term">on&#42;</span>&#160;can be used to refer to the group of potentially dangerous, script-accepting event attributes like <span class="term">onblur</span>&#160;and <span class="term">onchange</span>&#160;that have <span class="term">on</span>&#160;at the beginning of their names. Similarly, <span class="term">aria&#42;</span>&#160;and <span class="term">data&#42;</span>&#160;can be used to respectively refer to the set of all ARIA and data-* attributes.<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>&#160;(<a href="#s3.6">section 3.6</a>), the <span class="term">on&#42;</span>&#160;event attributes are automatically disallowed even if a value for <span class="term">$config["deny_attribute"]</span>&#160;has been manually provided.<br />
+<br />
+&#160; Note that attributes specified in <span class="term">$config["deny_attribute"]</span>&#160;are denied globally, for all elements. To deny attributes for only specific elements, <span class="term">$spec</span>&#160;(see <a href="#s2.3">section 2.3</a>) can be used. <span class="term">$spec</span>&#160;can also be used to element-specifically permit an attribute otherwise denied through <span class="term">$config["deny_attribute"]</span>.<br />
+<br />
+&#160; Finer restrictions on attributes can also be put into effect through <span class="term">$config["hook_tag"]</span>&#160;(<a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; <strong>Note</strong>: To deny all but a few attributes globally, a simpler way to specify <span class="term">$config["deny_attribute"]</span>&#160;would be to use the notation <span class="term">&#42; -attribute1 -attribute2 ...</span>. Thus, a value of <span class="term">&#42; -title -href</span>&#160;implies that except <span class="term">href</span>&#160;and <span class="term">title</span>&#160;(where allowed as per standards) all other attributes are to be removed. With this notation, the value for the parameter <span class="term">safe</span>&#160;(<a href="#s3.6">section 3.6</a>) will have no effect on <span class="term">deny_attribute</span>. Values of <span class="term">aria&#42;</span>&#160;<span class="term">data&#42;</span>, and <span class="term">on&#42;</span>&#160;cannot be used in this notation to refer to the sets of all ARIA, data-*, and on* attributes respectively.<br />
+<br />
+&#160; htmLawed (function <span class="term">hl_tag()</span>) also:<br />
+<br />
+&#160; * &#160;Lower-cases attribute names<br />
+&#160; * &#160;Removes duplicate attributes (last one stays)<br />
+&#160; * &#160;Gives attributes the form <span class="term">name="value"</span>&#160;and single-spaces them, removing unnecessary white-spacing<br />
+&#160; * &#160;Provides <em>required</em>&#160;attributes (see <a href="#s3.4.1">section 3.4.1</a>)<br />
+&#160; * &#160;Double-quotes values and escapes any <span class="term">"</span>&#160;inside them<br />
+&#160; * &#160;Replaces the possibly dangerous soft-hyphen characters (hexadecimal code-point <span class="term">ad</span>) in the values with spaces<br />
+&#160; * &#160;Allows custom function to additionally filter/modify attribute values (see <a href="#s3.4.9">section 3.4.9</a>)<br />
+
+<div class="sub-sub-section"><h4>
+<a name="s3.4.1" id="s3.4.1"></a><span class="item-no">3.4.1</span>&#160; Auto-addition of XHTML-required attributes
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If indicated attributes for the following elements are found missing, htmLawed (function <span class="term">hl_tag()</span>) will add them (with values same as attribute names unless indicated otherwise below):<br />
+<br />
+&#160; * &#160;area - alt (<span class="term">area</span>)<br />
+&#160; * &#160;area, img - src, alt (<span class="term">image</span>)<br />
+&#160; * &#160;bdo - dir (<span class="term">ltr</span>)<br />
+&#160; * &#160;form - action<br />
+&#160; * &#160;label - command<br />
+&#160; * &#160;map - name<br />
+&#160; * &#160;optgroup - label<br />
+&#160; * &#160;param - name<br />
+&#160; * &#160;style - scoped<br />
+&#160; * &#160;textarea - rows (<span class="term">10</span>), cols (<span class="term">50</span>)<br />
+<br />
+&#160; Additionally, with <span class="term">$config["xml&#58;lang"]</span>&#160;set to <span class="term">1</span>&#160;or <span class="term">2</span>, if the <span class="term">lang</span>&#160;but not the <span class="term">xml&#58;lang</span>&#160;attribute is declared, then the latter is added too, with a value copied from that of <span class="term">lang</span>. This is for better standard-compliance. With <span class="term">$config["xml&#58;lang"]</span>&#160;set to <span class="term">2</span>, the <span class="term">lang</span>&#160;attribute is removed (XHTML specification).<br />
+<br />
+&#160; Note that the <span class="term">name</span>&#160;attribute for <span class="term">map</span>, invalid in XHTML, is also transformed if required -- see <a href="#s3.4.6">section 3.4.6</a>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.2" id="s3.4.2"></a><span class="item-no">3.4.2</span>&#160; Duplicate/invalid <span class="term">id</span>&#160;values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["unique_ids"]</span>&#160;is <span class="term">1</span>, htmLawed (function <span class="term">hl_tag()</span>) removes <span class="term">id</span>&#160;attributes with values that are not standards-compliant (must not have a space character) or duplicate. If <span class="term">$config["unique_ids"]</span>&#160;is a word (without a non-word character like space), any duplicate but otherwise valid value will be appropriately prefixed with the word to ensure its uniqueness.<br />
+<br />
+&#160; Even if multiple inputs need to be filtered (through multiple calls to htmLawed), htmLawed ensures uniqueness of <span class="term">id</span>&#160;values as it uses a global variable (<span class="term">$GLOBALS["hl_Ids"]</span>&#160;array). Further, an admin can restrict the use of certain <span class="term">id</span>&#160;values by presetting this variable before htmLawed is called into use. E.g.:<br />
+<br />
+
+<code class="code">&#160; &#160; $GLOBALS[&#39;hl_Ids&#39;] = array(&#39;top&#39;=&gt;1, &#39;bottom&#39;=&gt;1, &#39;myform&#39;=&gt;1); // id values not allowed in input</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text); // filter input</code>
+<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.3" id="s3.4.3"></a><span class="item-no">3.4.3</span>&#160; URL schemes &amp; scripts in attribute values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed edits attributes that take URLs as values if they are found to contain un-permitted schemes. E.g., if the <span class="term">afp</span>&#160;scheme is not permitted, then <span class="term">&lt;a href="afp&#58;//domain.org"&gt;</span>&#160;becomes <span class="term">&lt;a href="denied&#58;afp&#58;//domain.org"&gt;</span>, and if Javascript is not permitted <span class="term">&lt;a onclick="javascript&#58;xss();"&gt;</span>&#160;becomes <span class="term">&lt;a onclick="denied&#58;javascript&#58;xss();"&gt;</span>.<br />
+<br />
+&#160; By default htmLawed permits these schemes in URLs for the <span class="term">href</span>&#160;attribute:<br />
+<br />
+
+<code class="code">&#160; &#160; aim, app, feed, file, ftp, gopher, http, https, javascript, irc, mailto, news, nntp, sftp, ssh, tel, telnet</code>
+<br />
+<br />
+&#160; Also, only <span class="term">data</span>, <span class="term">file</span>, <span class="term">http</span>, <span class="term">https</span>&#160;and <span class="term">javascript</span>&#160;are permitted in these attributes that accept URLs:<br />
+<br />
+
+<code class="code">&#160; &#160; action, cite, classid, codebase, data, itemtype, longdesc, model, pluginspage, pluginurl, src, srcset, style, usemap, and event attributes like onclick</code>
+<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>&#160;(<a href="#s3.6">section 3.6</a>), the above is changed to disallow <span class="term">app</span>, <span class="term">data</span>&#160;and <span class="term">javascript</span>.<br />
+<br />
+&#160; These default sets are used when <span class="term">$config["schemes"]</span>&#160;is not set (see <a href="#s2.2">section 2.2</a>). To over-ride the defaults, <span class="term">$config["schemes"]</span>&#160;is defined as a string of semi-colon-separated sub-strings of type <span class="term">attribute&#58; comma-separated schemes</span>. E.g., <span class="term">href&#58; mailto, http, https; onclick&#58; javascript; src&#58; http, https</span>. For unspecified attributes, <span class="term">data</span>, <span class="term">file</span>, <span class="term">http</span>, <span class="term">https</span>&#160;and <span class="term">javascript</span>&#160;are permitted. This can be changed by passing schemes for <span class="term">&#42;</span>&#160;in <span class="term">$config["schemes"]</span>. E.g., <span class="term">href&#58; mailto, http, https; &#42;&#58; https, https</span>.<br />
+<br />
+&#160; <span class="term">&#42;</span>&#160;(asterisk) can be put in the list of schemes to permit all protocols. E.g., <span class="term">style&#58; &#42;; img&#58; http, https</span>&#160;results in protocols not being checked in <span class="term">style</span>&#160;attribute values. However, in such cases, any relative-to-absolute URL conversion, or vice versa, (<a href="#s3.4.4">section 3.4.4</a>) is not done. When an attribute is explicitly listed in <span class="term">$config["schemes"]</span>, then filtering is dictated by the setting for the attribute, with no effect of the setting for asterisk. That is, the set of attributes that asterisk refers to no longer includes the listed attribute.<br />
+<br />
+&#160; Thus, <em>to allow the xmpp scheme</em>, one can set <span class="term">$config["schemes"]</span>&#160;as <span class="term">href&#58; mailto, http, https; &#42;&#58; http, https, xmpp</span>, or <span class="term">href&#58; mailto, http, https, xmpp; &#42;&#58; http, https, xmpp</span>, or <span class="term">&#42;&#58; &#42;</span>, and so on. The consequence of each of these example values will be different (e.g., only the last two but not the first will allow <span class="term">xmpp</span>&#160;in <span class="term">href</span>)<br />
+<br />
+&#160; As a side-note, one may find <span class="term">style&#58; &#42;</span>&#160;useful as URLs in <span class="term">style</span>&#160;attributes can be specified in a variety of ways, and the patterns that htmLawed uses to identify URLs may mistakenly identify non-URL text.<br />
+<br />
+&#160; <span class="term">!</span>&#160;can be put in the list of schemes to disallow all protocols as well as <em>local</em>&#160;URLs. Thus, with <span class="term">href&#58; http, style&#58; !</span>, <span class="term">&lt;a href="http&#58;//cnn.com" style="background-image&#58; url(local.jpg);"&gt;CNN&lt;/a&gt;</span>&#160;will become <span class="term">&lt;a href="http&#58;//cnn.com" style="background-image&#58; url(denied&#58;local.jpg);"&gt;CNN&lt;/a&gt;</span><br />
+<br />
+&#160; <strong>Note</strong>: If URL-accepting attributes other than those listed above are being allowed, then the scheme will not be checked unless the attribute name contains the string <span class="term">src</span>&#160;(e.g., <span class="term">dynsrc</span>) or starts with <span class="term">o</span>&#160;(e.g., <span class="term">onbeforecopy</span>).<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>, all URLs are disallowed in the <span class="term">style</span>&#160;attribute values.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.4" id="s3.4.4"></a><span class="item-no">3.4.4</span>&#160; Absolute &amp; relative URLs in attribute values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can make absolute URLs in attributes like <span class="term">href</span>&#160;relative (<span class="term">$config["abs_url"]</span>&#160;is <span class="term">-1</span>), and vice versa (<span class="term">$config["abs_url"]</span>&#160;is <span class="term">1</span>). URLs in scripts are not considered for this, and so are URLs like <span class="term">#section_6</span>&#160;(fragment), <span class="term">?name=Tim#show</span>&#160;(starting with query string), and <span class="term">;var=1?name=Tim#show</span>&#160;(starting with parameters). Further, this requires that <span class="term">$config["base_url"]</span>&#160;be set properly, with the <span class="term">&#58;//</span>&#160;and a trailing slash (<span class="term">/</span>), with no query string, etc. E.g., <span class="term">file&#58;///D&#58;/page/</span>, <span class="term">https&#58;//abc.com/x/y/</span>, or <span class="term">http&#58;//localhost/demo/</span>&#160;are okay, but <span class="term">file&#58;///D&#58;/page/?help=1</span>, <span class="term">abc.com/x/y/</span>&#160;and <span class="term">http&#58;//localhost/demo/index.htm</span>&#160;are not.<br />
+<br />
+&#160; For making absolute URLs relative, only those URLs that have the <span class="term">$config["base_url"]</span>&#160;string at the beginning are converted. E.g., with <span class="term">$config["base_url"] = "https&#58;//abc.com/x/y/"</span>, <span class="term">https&#58;//abc.com/x/y/a.gif</span>&#160;and <span class="term">https&#58;//abc.com/x/y/z/b.gif</span>&#160;become <span class="term">a.gif</span>&#160;and <span class="term">z/b.gif</span>&#160;respectively, while <span class="term">https&#58;//abc.com/x/c.gif</span>&#160;is not changed.<br />
+<br />
+&#160; When making relative URLs absolute, only values for scheme, network location (host-name) and path values in the base URL are inherited. See <a href="#s5.5">section 5.5</a>&#160;for more about the URL specification as per RFC <a href="http://www.ietf.org/rfc/rfc1808.txt">1808</a>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.5" id="s3.4.5"></a><span class="item-no">3.4.5</span>&#160; Lower-cased, standard attribute values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Optionally, for standard-compliance, htmLawed (function <span class="term">hl_tag()</span>) lower-cases standard attribute values to give, e.g., <span class="term">input type="password"</span>&#160;instead of <span class="term">input type="Password"</span>, if <span class="term">$config["lc_std_val"]</span>&#160;is <span class="term">1</span>. Attribute values matching those listed below for any of the elements listed further below (plus those for the <span class="term">type</span>&#160;attribute of <span class="term">button</span>&#160;or <span class="term">input</span>) are lower-cased:<br />
+<br />
+
+<code class="code">&#160; &#160; all, auto, baseline, bottom, button, captions, center, chapters, char, checkbox, circle, col, colgroup, color, cols, data, date, datetime, datetime-local, default, descriptions, email, file, get, groups, hidden, image, justify, left, ltr, metadata, middle, month, none, number, object, password, poly, post, preserve, radio, range, rect, ref, reset, right, row, rowgroup, rows, rtl, search, submit, subtitles, tel, text, time, top, url, week</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; a, area, bdo, button, col, fieldset, form, img, input, object, ol, optgroup, option, param, script, select, table, td, textarea, tfoot, th, thead, tr, track, xml&#58;space</code>
+<br />
+<br />
+&#160; The following <em>empty</em>&#160;(<em>minimized</em>) attributes are always assigned lower-cased values (same as the attribute names):<br />
+<br />
+
+<code class="code">&#160; &#160; checkbox, checked, command, compact, declare, defer, default, disabled, hidden, inert, ismap, itemscope, multiple, nohref, noresize, noshade, nowrap, open, radio, readonly, required, reversed, selected</code>
+<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.6" id="s3.4.6"></a><span class="item-no">3.4.6</span>&#160; Transformation of deprecated attributes
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["no_deprecated_attr"]</span>&#160;is <span class="term">0</span>, then deprecated attributes are removed and, in most cases, their values are transformed to CSS style properties and added to the <span class="term">style</span>&#160;attributes (function <span class="term">hl_tag()</span>). Except for <span class="term">bordercolor</span>&#160;for <span class="term">table</span>, <span class="term">tr</span>&#160;and <span class="term">td</span>, the scores of proprietary attributes that were never part of any cross-browser standard are not supported in this functionality.<br />
+<br />
+&#160; * &#160;align in caption, div, h, h2, h3, h4, h5, h6, hr, img, input, legend, object, p, table - for <span class="term">img</span>&#160;with value of <span class="term">left</span>&#160;or <span class="term">right</span>, becomes, e.g., <span class="term">float&#58; left</span>; for <span class="term">div</span>&#160;and <span class="term">table</span>&#160;with value <span class="term">center</span>, becomes <span class="term">margin&#58; auto</span>; all others become, e.g., <span class="term">text-align&#58; right</span><br />
+&#160; * &#160;bgcolor in table, td, th and tr - E.g., <span class="term">bgcolor="#ffffff"</span>&#160;becomes <span class="term">background-color&#58; #ffffff</span><br />
+&#160; * &#160;border in object - E.g., <span class="term">height="10"</span>&#160;becomes <span class="term">height&#58; 10px</span><br />
+&#160; * &#160;bordercolor in table, td and tr - E.g., <span class="term">bordercolor=#999999</span>&#160;becomes <span class="term">border-color&#58; #999999;</span><br />
+&#160; * &#160;compact in dl, ol and ul - <span class="term">font-size&#58; 85%</span><br />
+&#160; * &#160;cellspacing in table - <span class="term">cellspacing="10"</span>&#160;becomes <span class="term">border-spacing&#58; 10px</span><br />
+&#160; * &#160;clear in br - E.g., 'clear="all" becomes <span class="term">clear&#58; both</span><br />
+&#160; * &#160;height in td and th - E.g., <span class="term">height= "10"</span>&#160;becomes <span class="term">height&#58; 10px</span>&#160;and <span class="term">height="&#42;"</span>&#160;becomes <span class="term">height&#58; auto</span><br />
+&#160; * &#160;hspace in img and object - E.g., <span class="term">hspace="10"</span>&#160;becomes <span class="term">margin-left&#58; 10px; margin-right&#58; 10px</span><br />
+&#160; * &#160;language in script - <span class="term">language="VBScript"</span>&#160;becomes <span class="term">type="text/vbscript"</span><br />
+&#160; * &#160;name in a, form, iframe, img and map - E.g., <span class="term">name="xx"</span>&#160;becomes <span class="term">id="xx"</span><br />
+&#160; * &#160;noshade in hr - <span class="term">border-style&#58; none; border&#58; 0; background-color&#58; gray; color&#58; gray</span><br />
+&#160; * &#160;nowrap in td and th - <span class="term">white-space&#58; nowrap</span><br />
+&#160; * &#160;size in hr - E.g., <span class="term">size="10"</span>&#160;becomes <span class="term">height&#58; 10px</span><br />
+&#160; * &#160;vspace in img and object - E.g., <span class="term">vspace="10"</span>&#160;becomes <span class="term">margin-top&#58; 10px; margin-bottom&#58; 10px</span><br />
+&#160; * &#160;width in hr, pre, table, td and th - like <span class="term">height</span><br />
+<br />
+&#160; Example input:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;img src="j.gif" alt="image" name="dad&#39;s" /&gt;&lt;img src="k.gif" alt="image" id="dad_off" name="dad" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br clear="left" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;hr noshade size="1" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;img name="img" src="i.gif" align="left" alt="image" hspace="10" vspace="10" width="10em" height="20" border="1" style="padding&#58;5px;" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;table width="50em" align="center" bgcolor="red"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td width="20%"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;div align="center"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;h3 align="right"&gt;Section&lt;/h3&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;p align="right"&gt;Para&lt;/p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;/div&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td width="&#42;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;/tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/table&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br clear="all" /&gt;</code>
+<br />
+<br />
+&#160; And the output with <span class="term">$config["no_deprecated_attr"] = 1</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;img src="j.gif" alt="image" id="dad&#39;s" /&gt;&lt;img src="k.gif" alt="image" id="dad_off" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br style="clear&#58; left;" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;hr style="border-style&#58; none; border&#58; 0; background-color&#58; gray; color&#58; gray; size&#58; 1px;" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;img src="i.gif" alt="image" width="10em" height="20" style="padding&#58;5px; float&#58; left; margin-left&#58; 10px; margin-right&#58; 10px; margin-top&#58; 10px; margin-bottom&#58; 10px; border&#58; 1px;" id="img" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;table width="50em" style="margin&#58; auto; background-color&#58; red;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td style="width&#58; 20%;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;div style="margin&#58; auto;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;h3 style="text-align&#58; right;"&gt;Section&lt;/h3&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;p style="text-align&#58; right;"&gt;Para&lt;/p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;/div&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td style="width&#58; auto;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;/tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/table&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br style="clear&#58; both;" /&gt;</code>
+<br />
+<br />
+&#160; For <span class="term">lang</span>, deprecated in XHTML 1.1, transformation is taken care of through <span class="term">$config["xml&#58;lang"]</span>; see <a href="#s3.4.1">section 3.4.1</a>.<br />
+<br />
+&#160; The attribute <span class="term">name</span>&#160;is deprecated in <span class="term">form</span>, <span class="term">iframe</span>, and <span class="term">img</span>, and is replaced with <span class="term">id</span>&#160;if an <span class="term">id</span>&#160;attribute doesn't exist and if the <span class="term">name</span>&#160;value is appropriate for <span class="term">id</span>&#160;(i.e., doesn't have a non-word character like space). For such replacements for <span class="term">a</span>&#160;and <span class="term">map</span>, for which the <span class="term">name</span>&#160;attribute is deprecated in XHTML 1.1, <span class="term">$config["no_deprecated_attr"]</span>&#160;should be set to <span class="term">2</span>&#160;(when set to <span class="term">1</span>, for these two elements, the <span class="term">name</span>&#160;attribute is retained).<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.7" id="s3.4.7"></a><span class="item-no">3.4.7</span>&#160; Anti-spam &amp; <span class="term">href</span>
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed (function <span class="term">hl_tag()</span>) can check the <span class="term">href</span>&#160;attribute values (link addresses) as an anti-spam (email or link spam) measure.<br />
+<br />
+&#160; If <span class="term">$config["anti_mail_spam"]</span>&#160;is not <span class="term">0</span>, the <span class="term">@</span>&#160;of email addresses in <span class="term">href</span>&#160;values like <span class="term">mailto&#58;a@b.com</span>&#160;is replaced with text specified by <span class="term">$config["anti_mail_spam"]</span>. The text should be of a form that makes it clear to others that the address needs to be edited before a mail is sent; e.g., <span class="term">&lt;remove_this_antispam&gt;@</span>&#160;(makes the example address <span class="term">a&lt;remove_this_antispam&gt;@b.com</span>).<br />
+<br />
+&#160; For regular links, one can choose to have a <span class="term">rel</span>&#160;attribute with <span class="term">nofollow</span>&#160;in its value (which tells some search engines to not follow a link). This can discourage link spammers. Additionally, or as an alternative, one can choose to empty the <span class="term">href</span>&#160;value altogether (disable the link).<br />
+<br />
+&#160; For use of these options, <span class="term">$config["anti_link_spam"]</span>&#160;should be set as an array with values <span class="term">regex1</span>&#160;and <span class="term">regex2</span>, both or one of which can be empty (like <span class="term">array("", "regex2")</span>) to indicate that that option is not to be used. Otherwise, <span class="term">regex1</span>&#160;or <span class="term">regex2</span>&#160;should be PHP- and PCRE-compatible regular expression patterns: <span class="term">href</span>&#160;values will be matched against them and those matching the pattern will accordingly be treated.<br />
+<br />
+&#160; Note that the regular expressions should have <em>delimiters</em>, and be well-formed and preferably fast. Absolute efficiency/accuracy is often not needed.<br />
+<br />
+&#160; An example, to have a <span class="term">rel</span>&#160;attribute with <span class="term">nofollow</span>&#160;for all links, and to disable links that do not point to domains <span class="term">abc.com</span>&#160;and <span class="term">xyz.org</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; $config["anti_link_spam"] = array(&#39;&#96;.&#96;&#39;, &#39;&#96;&#58;//\W&#42;(?!(abc\.com|xyz\.org))&#96;&#39;);</code>
+<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.8" id="s3.4.8"></a><span class="item-no">3.4.8</span>&#160; Inline style properties
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can check URL schemes and dynamic expressions (to guard against Javascript, etc., script-based insecurities) in inline CSS style property values in the <span class="term">style</span>&#160;attributes. (CSS properties like <span class="term">background-image</span>&#160;that accept URLs in their values are noted in <a href="#s5.3">section 5.3</a>.) Dynamic CSS expressions that allow scripting in the IE browser, and can be a vulnerability, can be removed from property values by setting <span class="term">$config["css_expression"]</span>&#160;to <span class="term">1</span>&#160;(default setting). Note that when <span class="term">$config["css_expression"]</span>&#160;is set to <span class="term">1</span>, htmLawed will remove <span class="term">/&#42;</span>&#160;from the <span class="term">style</span>&#160;values.<br />
+<br />
+&#160; <strong>Note</strong>: Because of the various ways of representing characters in attribute values (URL-escapement, entitification, etc.), htmLawed might alter the values of the <span class="term">style</span>&#160;attribute values, and may even falsely identify dynamic CSS expressions and URL schemes in them. If this is an important issue, checking of URLs and dynamic expressions can be turned off (<span class="term">$config["schemes"] = "...style&#58;&#42;..."</span>, see <a href="#s3.4.3">section 3.4.3</a>, and <span class="term">$config["css_expression"] = 0</span>). Alternately, admins can use their own custom function for finer handling of <span class="term">style</span>&#160;values through the <span class="term">hook_tag</span>&#160;parameter (see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; It is also possible to have htmLawed let through any <span class="term">style</span>&#160;value by setting <span class="term">$config["style_pass"]</span>&#160;to <span class="term">1</span>.<br />
+<br />
+&#160; As such, it is better to set up a CSS file with class declarations, disallow the <span class="term">style</span>&#160;attribute, set a <span class="term">$spec</span>&#160;rule (see <a href="#s2.3">section 2.3</a>) for <span class="term">class</span>&#160;for the <span class="term">oneof</span>&#160;or <span class="term">match</span>&#160;parameter, and ask writers to make use of the <span class="term">class</span>&#160;attribute.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.9" id="s3.4.9"></a><span class="item-no">3.4.9</span>&#160; Hook function for tag content
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; It is possible to utilize a custom hook function to alter the tag content htmLawed has finalized (i.e., after it has checked/corrected for required attributes, transformed attributes, lower-cased attribute names, etc.).<br />
+<br />
+&#160; When <span class="term">$config</span>&#160;parameter <span class="term">hook_tag</span>&#160;is set to the name of a function, htmLawed (function <span class="term">hl_tag()</span>) will pass on the element name, and the <em>finalized</em>&#160;attribute name-value pairs as array elements to the function. The function, after completing a task such as filtering or tag transformation, will typically return an empty string, the full opening tag string like <span class="term">&lt;element_name attribute_1_name="attribute_1_value"...&gt;</span>&#160;(for empty elements like <span class="term">img</span>&#160;and <span class="term">input</span>, the element-closing slash <span class="term">/</span>&#160;should also be included), etc.<br />
+<br />
+&#160; Any <span class="term">hook_tag</span>&#160;function, since htmLawed version 1.1.11, also receives names of elements in closing tags, such as <span class="term">a</span>&#160;in the closing <span class="term">&lt;/a&gt;</span>&#160;tag of the element <span class="term">&lt;a href="http&#58;//cnn.com"&gt;CNN&lt;/a&gt;</span>. No other value is passed to the function since a closing tag contains only element names. Typically, the function will return an empty string or a full closing tag (like <span class="term">&lt;/a&gt;</span>).<br />
+<br />
+&#160; This is a <strong>powerful functionality</strong>&#160;that can be exploited for various objectives: consolidate-and-convert inline <span class="term">style</span>&#160;attributes to <span class="term">class</span>, convert <span class="term">embed</span>&#160;elements to <span class="term">object</span>, permit only one <span class="term">caption</span>&#160;element in a <span class="term">table</span>&#160;element, disallow embedding of certain types of media, <strong>inject HTML</strong>, use <a href="http://csstidy.sourceforge.net">CSSTidy</a>&#160;to sanitize <span class="term">style</span>&#160;attribute values, etc.<br />
+<br />
+&#160; As an example, the custom hook code below can be used to force a series of specifically ordered <span class="term">id</span>&#160;attributes on all elements, and a specific <span class="term">param</span>&#160;element inside all <span class="term">object</span>&#160;elements:<br />
+<br />
+
+<code class="code">&#160; &#160; function my_tag_function($element, $attribute_array=0){</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; // If second argument is not received, it means a closing tag is being handled</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; if(is_numeric($attribute_array)){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; return "&lt;/$element&gt;";</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; static $id = 0;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; // Remove any duplicate element</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; if($element == &#39;param&#39; &amp;&amp; isset($attribute_array[&#39;allowscriptaccess&#39;])){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; return &#39;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; $new_element = &#39;&#39;;</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; // Force a serialized ID number</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; $attribute_array[&#39;id&#39;] = &#39;my_&#39;. $id;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; ++$id;</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; // Inject param for allowscriptaccess</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; if($element == &#39;object&#39;){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; $new_element = &#39;&lt;param id="my_&#39;. $id. &#39;"; allowscriptaccess="never" /&gt;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; ++$id;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; $string = &#39;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; foreach($attribute_array as $k=&gt;$v){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; $string .= " {$k}=\"{$v}\"";</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; static $empty_elements = array(&#39;area&#39;=&gt;1, &#39;br&#39;=&gt;1, &#39;col&#39;=&gt;1, &#39;command&#39;=&gt;1, &#39;embed&#39;=&gt;1, &#39;hr&#39;=&gt;1, &#39;img&#39;=&gt;1, &#39;input&#39;=&gt;1, &#39;isindex&#39;=&gt;1, &#39;keygen&#39;=&gt;1, &#39;link&#39;=&gt;1, &#39;meta&#39;=&gt;1, &#39;param&#39;=&gt;1, &#39;source&#39;=&gt;1, &#39;track&#39;=&gt;1, &#39;wbr&#39;=&gt;1);</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; return "&lt;{$element}{$string}". (array_key_exists($element, $empty_elements) ? &#39; /&#39; &#58; &#39;&#39;). &#39;&gt;&#39;. $new_element;</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+<br />
+&#160; The <span class="term">hook_tag</span>&#160;parameter is different from the <span class="term">hook</span>&#160;parameter (<a href="#s3.7">section 3.7</a>).<br />
+<br />
+&#160; Snippets of hook function code developed by others may be available on the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">htmLawed</a>&#160;website.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.5" id="s3.5"></a><span class="item-no">3.5</span>&#160; Simple configuration directive for most valid XHTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["valid_xhtml"]</span>&#160;is set to <span class="term">1</span>, some relevant <span class="term">$config</span>&#160;parameters (indicated by <span class="term">~</span>&#160;in <a href="#s2.2">section 2.2</a>) are auto-adjusted. This allows one to pass the <span class="term">$config</span>&#160;argument with a simpler value. If a value for a parameter auto-set through <span class="term">valid_xhtml</span>&#160;is still manually provided, then that value will over-ride the auto-set value.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.6" id="s3.6"></a><span class="item-no">3.6</span>&#160; Simple configuration directive for most <em>safe</em>&#160;HTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <em>Safe</em>&#160;HTML refers to HTML that is restricted to reduce the vulnerability for scripting attacks (such as XSS) based on HTML code which otherwise may still be legal and compliant with the HTML standard specifications. When elements such as <span class="term">script</span>&#160;and <span class="term">object</span>, and attributes such as <span class="term">onmouseover</span>&#160;and <span class="term">style</span>&#160;are allowed in the input text, an input writer can introduce malevolent HTML code. Note that what is considered <span class="term">safe</span>&#160;depends on the nature of the web application and the trust-level accorded to its users.<br />
+<br />
+&#160; htmLawed allows an admin to use <span class="term">$config["safe"]</span>&#160;to auto-adjust multiple <span class="term">$config</span>&#160;parameters (such as <span class="term">elements</span>&#160;which declares the allowed element-set), which otherwise would have to be manually set. The relevant parameters are indicated by <span class="term">"</span>&#160;in <a href="#s2.2">section 2.2</a>). Thus, one can pass the <span class="term">$config</span>&#160;argument with a simpler value. Having the <span class="term">safe</span>&#160;parameter set to <span class="term">1</span>&#160;is equivalent to setting the following <span class="term">$config</span>&#160;parameters to the noted values :<br />
+<br />
+
+<code class="code">&#160; &#160; cdata - 0</code>
+<br />
+
+<code class="code">&#160; &#160; comment - 0</code>
+<br />
+
+<code class="code">&#160; &#160; deny_attribute - on&#42;</code>
+<br />
+
+<code class="code">&#160; &#160; elements - &#42; -applet -audio -canvas -embed -iframe -object -script -video</code>
+<br />
+
+<code class="code">&#160; &#160; schemes - href&#58; aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet; style&#58; !; &#42;&#58;file, http, https</code>
+<br />
+<br />
+&#160; With <span class="term">safe</span>&#160;set to <span class="term">1</span>, htmLawed considers <span class="term">CDATA</span>&#160;sections and HTML comments as plain text, and prohibits the <span class="term">applet</span>, <span class="term">audio</span>, <span class="term">canvas</span>, <span class="term">embed</span>, <span class="term">iframe</span>, <span class="term">object</span>, <span class="term">script</span>&#160;and <span class="term">video</span>&#160;elements, and the <span class="term">on&#42;</span>&#160;attributes like <span class="term">onclick</span>. ( There are <span class="term">$config</span>&#160;parameters like <span class="term">css_expression</span>&#160;that are not affected by the value set for <span class="term">safe</span>&#160;but whose default values still contribute towards a more <em>safe</em>&#160;output.) Further, unless overridden by the value for parameter <span class="term">schemes</span>&#160;(see <a href="#s3.4.3">section 3.4.3</a>), the schemes <span class="term">app</span>, <span class="term">data</span>&#160;and <span class="term">javascript</span>&#160;are not permitted, and URLs with schemes are neutralized so that, e.g., <span class="term">style="moz-binding&#58;url(http&#58;//danger)"</span>&#160;becomes <span class="term">style="moz-binding&#58;url(denied&#58;http&#58;//danger)"</span>.<br />
+<br />
+&#160; Admins, however, may still want to completely deny the <span class="term">style</span>&#160;attribute, e.g., with code like<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, array(&#39;safe&#39;=&gt;1, &#39;deny_attribute&#39;=&gt;&#39;style&#39;));</code>
+<br />
+<br />
+&#160; Permitting the <span class="term">style</span>&#160;attribute brings in risks of <em>click-jacking</em>, etc. CSS property values can render a page non-functional or be used to deface it. Except for URLs, dynamic expressions, and some other things, htmLawed does not completely check <span class="term">style</span>&#160;values. It does provide ways for the code-developer implementing htmLawed to do such checks through the <span class="term">$spec</span>&#160;argument, and through the <span class="term">hook_tag</span>&#160;parameter (see <a href="#s3.4.8">section 3.4.8</a>&#160;for more). Disallowing style completely and relying on CSS classes and stylesheet files is recommended.<br />
+<br />
+&#160; If a value for a parameter auto-set through <span class="term">safe</span>&#160;is still manually provided, then that value can over-ride the auto-set value. E.g., with <span class="term">$config["safe"] = 1</span>&#160;and <span class="term">$config["elements"] = "&#42; +script"</span>, <span class="term">script</span>, but not <span class="term">applet</span>, is allowed. Such over-ride does not occur for <span class="term">deny_attribute</span>&#160;(for legacy reason) when comma-separated attribute names are provided as the value for this parameter (<a href="#s3.4">section 3.4</a>); instead htmLawed will add <span class="term">on&#42;</span>&#160;to the value provided for <span class="term">deny_attribute</span>.<br />
+<br />
+&#160; A page illustrating the efficacy of htmLawed's anti-XSS abilities with <span class="term">safe</span>&#160;set to <span class="term">1</span>&#160;against XSS vectors listed by <a href="http://ha.ckers.org/xss.html">RSnake</a>&#160;may be available <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/rsnake/RSnakeXSSTest.htm">here</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.7" id="s3.7"></a><span class="item-no">3.7</span>&#160; Using a hook function
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["hook"]</span>&#160;is not set to <span class="term">0</span>, then htmLawed will allow preliminarily processed input to be altered by a hook function named by <span class="term">$config["hook"]</span>&#160;before starting the main work (but after handling of characters, entities, HTML comments and <span class="term">CDATA</span>&#160;sections -- see code for function <span class="term">htmLawed()</span>).<br />
+<br />
+&#160; The hook function also allows one to alter the <em>finalized</em>&#160;values of <span class="term">$config</span>&#160;and <span class="term">$spec</span>.<br />
+<br />
+&#160; Note that the <span class="term">hook</span>&#160;parameter is different from the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; Snippets of hook function code developed by others may be available on the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">htmLawed</a>&#160;website.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.8" id="s3.8"></a><span class="item-no">3.8</span>&#160; Obtaining <em>finalized</em>&#160;parameter values
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can assign the <em>finalized</em>&#160;<span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;values to a variable named by <span class="term">$config["show_setting"]</span>. The variable, made global by htmLawed, is set as an array with three keys: <span class="term">config</span>, with the <span class="term">$config</span>&#160;value, <span class="term">spec</span>, with the <span class="term">$spec</span>&#160;value, and <span class="term">time</span>, with a value that is the Unix time (the output of PHP's <span class="term">microtime()</span>&#160;function) when the value was assigned. Admins should use a PHP-compliant variable name (e.g., one that does not begin with a numerical digit) that does not conflict with variable names in their non-htmLawed code.<br />
+<br />
+&#160; The values, which are also post-hook function (if any), can be used to auto-generate information (on, e.g., the elements that are permitted) for input writers.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.9" id="s3.9"></a><span class="item-no">3.9</span>&#160; Retaining non-HTML tags in input with mixed markup
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed does not remove certain characters that, though invalid, are nevertheless <em>discouraged</em>&#160;in HTML documents as per the specifications (see <a href="#s5.1">section 5.1</a>). This can be utilized to deal with input that contains mixed markup. Input that may have HTML markup as well as some other markup that is based on the <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters is considered to have mixed markup. The non-HTML markup can be rather proprietary (like markup for emoticons/smileys), or standard (like MathML or SVG). Or it can be programming code meant for execution/evaluation (such as embedded PHP code).<br />
+<br />
+&#160; To deal with such mixed markup, the input text can be pre-processed to hide the non-HTML markup by specifically replacing the <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters with some of the HTML-discouraged characters (see <a href="#s3.1.2">section 3.1.2</a>). Post-htmLawed processing, the replacements are reverted.<br />
+<br />
+&#160; An example (mixed HTML and PHP code in input text):<br />
+<br />
+
+<code class="code">&#160; &#160; $text = preg_replace(&#39;&#96;&lt;\?php(.+?)\?&gt;&#96;sm&#39;, "\x83?php\\1?\x84", $text);</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text);</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = preg_replace(&#39;&#96;\x83\?php(.+?)\?\x84&#96;sm&#39;, &#39;&lt;?php$1?&gt;&#39;, $processed);</code>
+<br />
+<br />
+&#160; This code will not work if <span class="term">$config["clean_ms_char"]</span>&#160;is set to <span class="term">1</span>&#160;(<a href="#s3.1">section 3.1</a>), in which case one should instead deploy a hook function (<a href="#s3.7">section 3.7</a>). (htmLawed internally uses certain control characters, code-points <span class="term">1</span>&#160;to <span class="term">7</span>, and use of these characters as markers in the logic of hook functions may cause issues.)<br />
+<br />
+&#160; Admins may also be able to use <span class="term">$config["and_mark"]</span>&#160;to deal with such mixed markup; see <a href="#s3.2">section 3.2</a>.<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s4" id="s4"></a><span class="item-no">4</span>&#160; Other
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<div class="sub-section"><h3>
+<a name="s4.1" id="s4.1"></a><span class="item-no">4.1</span>&#160; Support
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Software updates and forum-based community-support may be found at <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>. For general PHP issues (not htmLawed-specific), support may be found through internet searches and at <a href="http://php.net">http://php.net</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.2" id="s4.2"></a><span class="item-no">4.2</span>&#160; Known issues
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; See <a href="#s2.8">section 2.8</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.3" id="s4.3"></a><span class="item-no">4.3</span>&#160; Change-log
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; (The release date for the downloadable package of files containing documentation, demo script, test-cases, etc., besides the <span class="term">htmLawed.php</span>&#160;file, may be updated without a change-log entry if the secondary files, but not htmLawed per se, are revised.)<br />
+<br />
+&#160; <em>Version number - Release date. Notes</em><br />
+<br />
+&#160; 1.2.6 - 4 September 2021. Fixes a bug that arises when <span class="term">$config["deny_attribute"]</span>&#160;has a <span class="term">data-&#42;</span>&#160;attribute with &gt; 1 hyphen character<br />
+<br />
+&#160; 1.2.5 - 24 September 2019. Fixes two bugs in <span class="term">font</span>&#160;tag transformation<br />
+<br />
+&#160; 1.2.4.2 - 16 May 2019. Corrects a PHP notice if a semi-colon is present in <span class="term">$config["schemes"]</span><br />
+<br />
+&#160; 1.2.4.1 - 12 September 2017. Corrects a function re-declaration bug introduced in version 1.2.4<br />
+<br />
+&#160; 1.2.4 - 31 August 2017. Removes use of PHP <span class="term">create_function</span>&#160;function and <span class="term">$php_errormsg</span>&#160;reserved variable (deprecated in PHP 7.2)<br />
+<br />
+&#160; 1.2.3 - 5 July 2017. New option value of <span class="term">4</span>&#160;for <span class="term">$config["comments"]</span>&#160;to stop enforcing a space character before the <span class="term">--&gt;</span>&#160;comment-closing marker<br />
+<br />
+&#160; 1.2.2 - 25 May 2017. Fix for a bug in parsing <span class="term">$spec</span>&#160;that got introduced in version 1.2; also, <span class="term">$spec</span>&#160;is now parsed to accommodate specifications for an HTML element when they are specified in multiple rules<br />
+<br />
+&#160; 1.2.1.1 - 17 May 2017. Fix for a potential security vulnerability in transformation of deprecated attributes<br />
+<br />
+&#160; 1.2.1 - 15 May 2017. Fix for a potential security vulnerability in transformation of deprecated attributes<br />
+<br />
+&#160; 1.2 - 11 February 2017. (First beta release on 26 May 2013). Added support for HTML version 5; ARIA, data-* and microdata attributes; <span class="term">app</span>, <span class="term">data</span>, <span class="term">javascript</span>&#160;and <span class="term">tel</span>&#160;URL schemes (thus, <span class="term">javascript&#58;</span>&#160;is not filtered in default mode). Removed support for code using Kses functions (see <a href="#s2.6">section 2.6</a>). Changes in revisions to the beta releases are not noted here.<br />
+<br />
+&#160; 1.1.22 - 5 March 2016. Improved testing of attribute value rules specified in <span class="term">$spec</span><br />
+<br />
+&#160; 1.1.21 - 27 February 2016. Improvement and security fix in transforming <span class="term">font</span>&#160;element<br />
+<br />
+&#160; 1.1.20 - 9 June 2015. Fix for a potential security vulnerability arising from unescaped double-quote character in single-quoted attribute value of some deprecated elements when tag transformation is enabled; recognition for non-(HTML 4) standard <span class="term">allowfullscreen</span>&#160;attribute of <span class="term">iframe</span><br />
+<br />
+&#160; 1.1.19 - 19 January 2015. Fix for a bug in cleaning of soft-hyphens in URL values, etc<br />
+<br />
+&#160; 1.1.18 - 2 August 2014. Fix for a potential security vulnerability arising from specially encoded text with serial opening tags<br />
+<br />
+&#160; 1.1.17 - 11 March 2014. Removed use of PHP function preg_replace with <span class="term">e</span>&#160;modifier for compatibility with PHP 5.5.<br />
+<br />
+&#160; 1.1.16 - 29 August 2013. Fix for a potential security vulnerability arising from specialy encoded space characters in URL schemes/protocols<br />
+<br />
+&#160; 1.1.15 - 11 August 2013. Improved tidying/prettifying functionality<br />
+<br />
+&#160; 1.1.14 - 8 August 2012. Fix for possible segmental loss of incremental indentation during <span class="term">tidying</span>&#160;when <span class="term">balance</span>&#160;is disabled; fix for non-effectuation under some circumstances of a corrective behavior to preserve plain text within elements like <span class="term">blockquote</span><br />
+<br />
+&#160; 1.1.13 - 22 July 2012. Added feature allowing use of custom, non-standard attributes or custom rules for standard attributes<br />
+<br />
+&#160; 1.1.12 - 5 July 2012. Fix for a bug in identifying an unquoted value of the <span class="term">face</span>&#160;attribute<br />
+<br />
+&#160; 1.1.11 - 5 June 2012. Fix for possible problem with handling of multi-byte characters in attribute values in an mbstring.func_overload enviroment. <span class="term">$config["hook_tag"]</span>, if specified, now receives names of elements in closing tags.<br />
+<br />
+&#160; 1.1.10 - 22 October 2011. Fix for a bug in the <span class="term">tidy</span>&#160;functionality that caused the entire input to be replaced with a single space; new parameter, <span class="term">$config["direct_list_nest"]</span>&#160;to allow direct descendance of a list in a list. (5 April 2012. Dual licensing from LGPLv3 to LGPLv3 and GPLv2+.)<br />
+<br />
+&#160; 1.1.9.5 - 6 July 2011. Minor correction of a rule for nesting of <span class="term">li</span>&#160;within <span class="term">dir</span><br />
+<br />
+&#160; 1.1.9.4 - 3 July 2010. Parameter <span class="term">schemes</span>&#160;now accepts <span class="term">!</span>&#160;so any URL, even a local one, can be <em>denied</em>. An issue in which a second URL value in <span class="term">style</span>&#160;properties was not checked was fixed.<br />
+<br />
+&#160; 1.1.9.3 - 17 May 2010. Checks for correct nesting of <span class="term">param</span><br />
+<br />
+&#160; 1.1.9.2 - 26 April 2010. Minor fix regarding rendering of denied URL schemes<br />
+<br />
+&#160; 1.1.9.1 - 26 February 2010. htmLawed now uses the LGPL version 3 license; support for <span class="term">flashvars</span>&#160;attribute for <span class="term">embed</span><br />
+<br />
+&#160; 1.1.9 - 22 December 2009. Soft-hyphens are now removed only from URL-accepting attribute values<br />
+<br />
+&#160; 1.1.8.1 - 16 July 2009. Minor code-change to fix a PHP error notice<br />
+<br />
+&#160; 1.1.8 - 23 April 2009. Parameter <span class="term">deny_attribute</span>&#160;now accepts the wild-card <span class="term">&#42;</span>, making it simpler to specify its value when all but a few attributes are being denied; fixed a bug in interpreting <span class="term">$spec</span><br />
+<br />
+&#160; 1.1.7 - 11-12 March 2009. Attributes globally denied through <span class="term">deny_attribute</span>&#160;can be allowed element-specifically through <span class="term">$spec</span>; <span class="term">$config["style_pass"]</span>&#160;allowing letting through any <span class="term">style</span>&#160;value introduced; altered logic to catch certain types of dynamic crafted CSS expressions<br />
+<br />
+&#160; 1.1.3-6 - 28-31 January - 4 February 2009. Altered logic to catch certain types of dynamic crafted CSS expressions<br />
+<br />
+&#160; 1.1.2 - 22 January 2009. Fixed bug in parsing of <span class="term">font</span>&#160;attributes during tag transformation<br />
+<br />
+&#160; 1.1.1 - 27 September 2008. Better nesting correction when omitable closing tags are absent<br />
+<br />
+&#160; 1.1 - 29 June 2008. <span class="term">$config["hook_tag"]</span>&#160;and <span class="term">$config["tidy"]</span>&#160;introduced for custom tag/attribute check/modification/injection and output compaction/beautification; fixed a regex-in-$spec parsing bug<br />
+<br />
+&#160; 1.0.9 - 11 June 2008. Fix for a bug in checks for invalid HTML code-point entities<br />
+<br />
+&#160; 1.0.8 - 15 May 2008. Permit <span class="term">bordercolor</span>&#160;attribute for <span class="term">table</span>, <span class="term">td</span>&#160;and <span class="term">tr</span><br />
+<br />
+&#160; 1.0.7 - 1 May 2008. Support for <span class="term">wmode</span>&#160;attribute for <span class="term">embed</span>; <span class="term">$config["show_setting"]</span>&#160;introduced; improved <span class="term">$config["elements"]</span>&#160;evaluation<br />
+<br />
+&#160; 1.0.6 - 20 April 2008. <span class="term">$config["and_mark"]</span>&#160;introduced<br />
+<br />
+&#160; 1.0.5 - 12 March 2008. <span class="term">style</span>&#160;URL schemes essentially disallowed when $config <span class="term">safe</span>&#160;is on; improved regex for CSS expression search<br />
+<br />
+&#160; 1.0.4 - 10 March 2008. Improved corrections for <span class="term">blockquote</span>, <span class="term">form</span>, <span class="term">map</span>&#160;and <span class="term">noscript</span><br />
+<br />
+&#160; 1.0.3 - 3 March 2008. Character entities for soft-hyphens are now replaced with spaces (instead of being removed); fix for a bug allowing <span class="term">td</span>&#160;directly inside <span class="term">table</span>; <span class="term">$config["safe"]</span>&#160;introduced<br />
+<br />
+&#160; 1.0.2 - 13 February 2008. Improved implementation of <span class="term">$config["keep_bad"]</span><br />
+<br />
+&#160; 1.0.1 - 7 November 2007. Improved regex for identifying URLs, protocols and dynamic expressions (<span class="term">hl_tag()</span>&#160;and <span class="term">hl_prot()</span>); no error display with <span class="term">hl_regex()</span><br />
+<br />
+&#160; 1.0 - 2 November 2007. First release<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.4" id="s4.4"></a><span class="item-no">4.4</span>&#160; Testing
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; To test htmLawed using a form interface, a <a href="htmLawedTest.php">demo</a>&#160;web-page is provided with the htmLawed distribution (<span class="term">htmLawed.php</span>&#160;and <span class="term">htmLawedTest.php</span>&#160;should be in the same directory on the web-server). A file with <a href="htmLawed_TESTCASE.txt">test-cases</a>&#160;is also provided.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.5" id="s4.5"></a><span class="item-no">4.5</span>&#160; Upgrade, &amp; old versions
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Upgrading is as simple as replacing the previous version of <span class="term">htmLawed.php</span>, assuming the file was not modified for customized features. As htmLawed output is almost always used in static documents, upgrading should not affect old, finalized content.<br />
+<br />
+&#160; <strong>Note:</strong>&#160;The following upgrades may affect the functionality of a specific htmLawed installation:<br />
+<br />
+&#160; (1) From version 1.1-1.1.10 to 1.1.11 or later, if a <span class="term">hook_tag</span>&#160;function is in use: In version 1.1.11 and later, elements in closing tags (and not just the opening tags) are also passed to the function. There are no attribute names/values to pass, so a <span class="term">hook_tag</span>&#160;function receives only the element name. The <span class="term">hook_tag</span>&#160;function therefore may have to be edited. See <a href="#s3.4.9">section 3.4.9</a>.<br />
+<br />
+&#160; (2) From version older than 1.2.beta to later, if htmLawed was used as Kses replacement with Kses code in use: In version 1.2.beta or later, htmLawed no longer provides direct support for code that uses Kses functions (see <a href="#s2.6">section 2.6</a>).<br />
+<br />
+&#160; (3) From version older than 1.2 to later, if htmLawed is used without <span class="term">$config["safe"]</span>&#160;set to 1: Unlike previous versions, htmLawed version 1.2 and later permit <span class="term">data</span>&#160;and <span class="term">javascript</span>&#160;URL schemes by default (see <a href="#s3.4.3">section 3.4.3</a>).<br />
+<br />
+&#160; Old versions of htmLawed may be available online. E.g., for version 1.0, check <a href="http://www.bioinformatics.org/phplabware/downloads/htmLawed1.zip">http://www.bioinformatics.org/phplabware/downloads/htmLawed1.zip</a>; for 1.1.1, <a href="http://www.bioinformatics.org/phplabware/downloads/htmLawed111.zip">http://www.bioinformatics.org/phplabware/downloads/htmLawed111.zip</a>; and for 1.1.22, <a href="http://www.bioinformatics.org/phplabware/downloads/htmLawed1122.zip">http://www.bioinformatics.org/phplabware/downloads/htmLawed1122.zip</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.6" id="s4.6"></a><span class="item-no">4.6</span>&#160; Comparison with <span class="term">HTMLPurifier</span>
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The HTMLPurifier PHP library by Edward Yang is a very good HTML filtering script that uses object oriented PHP code. Compared to htmLawed, it (as of year 2015):<br />
+<br />
+&#160; * &#160;does not support PHP versions older than 5.0 (HTMLPurifier dropped PHP 4 support after version 2)<br />
+<br />
+&#160; * &#160;is 15-20 times bigger (scores of files totalling more than 750 kb)<br />
+<br />
+&#160; * &#160;consumes 10-15 times more RAM memory (just including the HTMLPurifier files without calling the filter requires a few MBs of memory)<br />
+<br />
+&#160; * &#160;is expectedly slower<br />
+<br />
+&#160; * &#160;lacks many of the extra features of htmLawed (like entity conversions and code compaction/beautification)<br />
+<br />
+&#160; * &#160;has poor documentation<br />
+<br />
+&#160; However, HTMLPurifier has finer checks for character encodings and attribute values, and can log warnings and errors. Visit the HTMLPurifier <a href="http://htmlpurifier.org">website</a>&#160;for updated information.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.7" id="s4.7"></a><span class="item-no">4.7</span>&#160; Use through application plug-ins/modules
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Plug-ins/modules to implement htmLawed in applications such as Drupal may have been developed. Check the application websites and the htmLawed <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">forum</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.8" id="s4.8"></a><span class="item-no">4.8</span>&#160; Use in non-PHP applications
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Non-PHP applications written in Python, Ruby, etc., may be able to use htmLawed through system calls to the PHP engine. Such code may have been documented on the internet. Also check the forum on the htmLawed <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">site</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.9" id="s4.9"></a><span class="item-no">4.9</span>&#160; Donate
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; A donation in any currency and amount to appreciate or support this software can be sent by <a href="http://paypal.com">PayPal</a>&#160;to this email address: drpatnaik at yahoo dot com.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.10" id="s4.10"></a><span class="item-no">4.10</span>&#160; Acknowledgements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Nicholas Alipaz, Bryan Blakey, Pádraic Brady, Dac Chartrand, Alexandre Chouinard, Ulf Harnhammer, Gareth Heyes, Hakre, Klaus Leithoff, Lukasz Pilorz, Shelley Powers, Psych0tr1a, Lincoln Russell, Tomas Sykorka, Harro Verton, Edward Yang, and many anonymous users.<br />
+<br />
+&#160; Thank you!<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s5" id="s5"></a><span class="item-no">5</span>&#160; Appendices
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<div class="sub-section"><h3>
+<a name="s5.1" id="s5.1"></a><span class="item-no">5.1</span>&#160; Characters discouraged in XHTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Characters represented by the following hexadecimal code-points are <em>not</em>&#160;invalid, even though some validators may issue messages stating otherwise.<br />
+<br />
+&#160; <span class="term">7f</span>&#160;to <span class="term">84</span>, <span class="term">86</span>&#160;to <span class="term">9f</span>, <span class="term">fdd0</span>&#160;to <span class="term">fddf</span>, <span class="term">1fffe</span>, <span class="term">1ffff</span>, <span class="term">2fffe</span>, <span class="term">2ffff</span>, <span class="term">3fffe</span>, <span class="term">3ffff</span>, <span class="term">4fffe</span>, <span class="term">4ffff</span>, <span class="term">5fffe</span>, <span class="term">5ffff</span>, <span class="term">6fffe</span>, <span class="term">6ffff</span>, <span class="term">7fffe</span>, <span class="term">7ffff</span>, <span class="term">8fffe</span>, <span class="term">8ffff</span>, <span class="term">9fffe</span>, <span class="term">9ffff</span>, <span class="term">afffe</span>, <span class="term">affff</span>, <span class="term">bfffe</span>, <span class="term">bffff</span>, <span class="term">cfffe</span>, <span class="term">cffff</span>, <span class="term">dfffe</span>, <span class="term">dffff</span>, <span class="term">efffe</span>, <span class="term">effff</span>, <span class="term">ffffe</span>, <span class="term">fffff</span>, <span class="term">10fffe</span>&#160;and <span class="term">10ffff</span><br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.2" id="s5.2"></a><span class="item-no">5.2</span>&#160; Valid attribute-element combinations
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; * &#160;includes deprecated attributes (marked <span class="term">^</span>), attributes for microdata (marked <span class="term">&#42;</span>), the non-standard <span class="term">bordercolor</span>, and new-in-HTML5 attributes (marked <span class="term">~</span>); can have multiple comma-separated values (marked <span class="term">%</span>); can have multiple space-separated values (marked <span class="term">$</span>)<br />
+&#160; * &#160;only non-frameset, HTML body elements<br />
+&#160; * &#160;<span class="term">name</span>&#160;for <span class="term">a</span>&#160;and <span class="term">map</span>, and <span class="term">lang</span>&#160;are invalid in XHTML 1.1<br />
+&#160; * &#160;<span class="term">target</span>&#160;is valid for <span class="term">a</span>&#160;in XHTML 1.1 and higher<br />
+&#160; * &#160;<span class="term">xml&#58;space</span>&#160;is only for XHTML 1.1<br />
+<br />
+&#160; abbr - td, th<br />
+&#160; accept - form, input<br />
+&#160; accept-charset - form<br />
+&#160; action - form<br />
+&#160; align - applet, caption^, col, colgroup, div^, embed, h1^, h2^, h3^, h4^, h5^, h6^, hr^, iframe, img^, input^, legend^, object^, p^, table^, tbody, td, tfoot, th, thead, tr<br />
+&#160; allowfullscreen - iframe<br />
+&#160; alt - applet, area, img, input<br />
+&#160; archive - applet, object<br />
+&#160; async~ - script<br />
+&#160; autocomplete~ - input<br />
+&#160; autofocus~ - button, input, keygen, select, textarea<br />
+&#160; autoplay~ - audio, video<br />
+&#160; axis - td, th<br />
+&#160; bgcolor - embed, table^, td^, th^, tr^<br />
+&#160; border - img, object^, table<br />
+&#160; bordercolor - table, td, tr<br />
+&#160; cellpadding - table<br />
+&#160; cellspacing - table<br />
+&#160; challenge~ - keygen<br />
+&#160; char - col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; charoff - col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; charset - a, script<br />
+&#160; checked - command, input<br />
+&#160; cite - blockquote, del, ins, q<br />
+&#160; classid - object<br />
+&#160; clear - br^<br />
+&#160; code - applet<br />
+&#160; codebase - object, applet<br />
+&#160; codetype - object<br />
+&#160; color - font<br />
+&#160; cols - textarea<br />
+&#160; colspan - td, th<br />
+&#160; compact - dir, dl^, menu, ol^, ul^<br />
+&#160; content - meta<br />
+&#160; controls~ - audio, video<br />
+&#160; coords - area, a<br />
+&#160; crossorigin~ - img<br />
+&#160; data - object<br />
+&#160; datetime - del, ins, time<br />
+&#160; declare - object<br />
+&#160; default~ - track<br />
+&#160; defer - script<br />
+&#160; dir - bdo<br />
+&#160; dirname~ - input, textarea<br />
+&#160; disabled - button, command, fieldset, input, keygen, optgroup, option, select, textarea<br />
+&#160; download~ - a<br />
+&#160; enctype - form<br />
+&#160; face - font<br />
+&#160; flashvars** - embed<br />
+&#160; for - label, output<br />
+&#160; form~ - button, fieldset, input, keygen, label, object, output, select, textarea<br />
+&#160; formaction~ - button, input<br />
+&#160; formenctype~ - button, input<br />
+&#160; formmethod~ - button, input<br />
+&#160; formnovalidate~ - button, input<br />
+&#160; formtarget~ - button, input<br />
+&#160; frame - table<br />
+&#160; frameborder - iframe<br />
+&#160; headers - td, th<br />
+&#160; height - applet, canvas, embed, iframe, img, input, object, td^, th^, video<br />
+&#160; high~ - meter<br />
+&#160; href - a, area, link<br />
+&#160; hreflang - a, area, link<br />
+&#160; hspace - applet, embed, img^, object^<br />
+&#160; icon~ - command<br />
+&#160; ismap - img, input<br />
+&#160; keytype~ - keygen<br />
+&#160; keyparams~ - keygen<br />
+&#160; kind~ - track<br />
+&#160; label - command, menu, option, optgroup, track<br />
+&#160; language - script^<br />
+&#160; list~ - input<br />
+&#160; longdesc - img, iframe<br />
+&#160; loop~ - audio, video<br />
+&#160; low~ - meter<br />
+&#160; marginheight - iframe<br />
+&#160; marginwidth - iframe<br />
+&#160; max~ - input, meter, progress<br />
+&#160; maxlength - input, textarea<br />
+&#160; media~ - a, area, link, source, style<br />
+&#160; mediagroup~ - audio, video<br />
+&#160; method - form<br />
+&#160; min~ - input, meter<br />
+&#160; model** - embed<br />
+&#160; multiple - input, select<br />
+&#160; muted~ - audio, video<br />
+&#160; name - a^, applet^, button, embed, fieldset, form^, iframe^, img^, input, keygen, map^, object, output, param, select, textarea<br />
+&#160; nohref - area<br />
+&#160; noshade - hr^<br />
+&#160; novalidate~ - form<br />
+&#160; nowrap - td^, th^<br />
+&#160; object - applet<br />
+&#160; open~ - details<br />
+&#160; optimum~ - meter<br />
+&#160; pattern~ - input<br />
+&#160; ping~ - a, area<br />
+&#160; placeholder~ - input, textarea<br />
+&#160; pluginspage** - embed<br />
+&#160; pluginurl** - embed<br />
+&#160; poster~ - video<br />
+&#160; pqg~ - keygen<br />
+&#160; preload~ - audio, video<br />
+&#160; prompt - isindex<br />
+&#160; pubdate~ - time<br />
+&#160; radiogroup* - command<br />
+&#160; readonly - input, textarea<br />
+&#160; required~ - input, select, textarea<br />
+&#160; rel$ - a, area, link<br />
+&#160; rev - a<br />
+&#160; reversed~ - old<br />
+&#160; rows - textarea<br />
+&#160; rowspan - td, th<br />
+&#160; rules - table<br />
+&#160; sandbox~ - iframe<br />
+&#160; scope - td, th<br />
+&#160; scoped~ - style<br />
+&#160; scrolling - iframe<br />
+&#160; seamless~ - iframe<br />
+&#160; selected - option<br />
+&#160; shape - area, a<br />
+&#160; size - font, hr^, input, select<br />
+&#160; sizes~ - link<br />
+&#160; span - col, colgroup<br />
+&#160; src - audio, embed, iframe, img, input, script, source, track, video<br />
+&#160; srcdoc~ - iframe<br />
+&#160; srclang~ - track<br />
+&#160; srcset~% - img<br />
+&#160; standby - object<br />
+&#160; start - ol<br />
+&#160; step~ - input<br />
+&#160; summary - table<br />
+&#160; target - a, area, form<br />
+&#160; type - a, area, button, command, embed, input, li, link, menu, object, ol, param, script, source, style, ul<br />
+&#160; typemustmatch~ - object<br />
+&#160; usemap - img, input, object<br />
+&#160; valign - col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; value - button, data, input, li, meter, option, param, progress<br />
+&#160; valuetype - param<br />
+&#160; vspace - applet, embed, img^, object^<br />
+&#160; width - applet, canvas, col, colgroup, embed, hr^, iframe, img, input, object, pre^, table, td^, th^, video<br />
+&#160; wmode - embed<br />
+&#160; wrap~ - textarea<br />
+<br />
+&#160; The following attributes, including event-specific ones and attributes of ARIA and microdata specifications, are considered global and allowed in all elements:<br />
+<br />
+&#160; accesskey, aria-activedescendant, aria-atomic, aria-autocomplete, aria-busy, aria-checked, aria-controls, aria-describedby, aria-disabled, aria-dropeffect, aria-expanded, aria-flowto, aria-grabbed, aria-haspopup, aria-hidden, aria-invalid, aria-label, aria-labelledby, aria-level, aria-live, aria-multiline, aria-multiselectable, aria-orientation, aria-owns, aria-posinset, aria-pressed, aria-readonly, aria-relevant, aria-required, aria-selected, aria-setsize, aria-sort, aria-valuemax, aria-valuemin, aria-valuenow, aria-valuetext, class$, contenteditable, contextmenu, dir, draggable, dropzone, hidden, id, inert, itemid, itemprop, itemref, itemscope, itemtype, lang, onabort, onblur, oncanplay, oncanplaythrough, onchange, onclick, oncontextmenu, oncopy, oncuechange, oncut, ondblclick, ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, onerror, onfocus, onformchange, onforminput, oninput, oninvalid, onkeydown, onkeypress, onkeyup, onload, onloadeddata, onloadedmetadata, onloadstart, onlostpointercapture, onmousedown, onmousemove, onmouseout, onmouseover, onmouseup, onmousewheel, onpaste, onpause, onplay, onplaying, onpointercancel, ongotpointercapture, onpointerdown, onpointerenter, onpointerleave, onpointermove, onpointerout, onpointerover, onpointerup, onprogress, onratechange, onreadystatechange, onreset, onsearch, onscroll, onseeked, onseeking, onselect, onshow, onstalled, onsubmit, onsuspend, ontimeupdate, ontoggle, ontouchcancel, ontouchend, ontouchmove, ontouchstart, onvolumechange, onwaiting, onwheel, role, spellcheck, style, tabindex, title, translate, xmlns, xml:base, xml:lang, xml:space<br />
+<br />
+&#160; Custom <em>data-*</em>&#160;attributes, where the first three characters of the value of <em>star</em>&#160;(*) after lower-casing do not equal <span class="term">xml</span>&#160;and the value of <em>star</em>&#160;does not have a colon (:), equal-to (=), newline, solidus (/), space, tab, or any A-Z character, are also considered global and allowed in all elements.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.3" id="s5.3"></a><span class="item-no">5.3</span>&#160; CSS 2.1 properties accepting URLs
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; background<br />
+&#160; background-image<br />
+&#160; content<br />
+&#160; cue-after<br />
+&#160; cue-before<br />
+&#160; cursor<br />
+&#160; list-style<br />
+&#160; list-style-image<br />
+&#160; play-during<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.4" id="s5.4"></a><span class="item-no">5.4</span>&#160; Microsoft Windows 1252 character replacements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Key: <span class="term">d</span>&#160;double, <span class="term">l</span>&#160;left, <span class="term">q</span>&#160;quote, <span class="term">r</span>&#160;right, <span class="term">s.</span>&#160;single<br />
+<br />
+&#160; Code-point (decimal) - hexadecimal value - replacement entity - represented character<br />
+<br />
+&#160; 127 - 7f - (removed) - (not used)<br />
+&#160; 128 - 80 - &amp;#8364; - euro<br />
+&#160; 129 - 81 - (removed) - (not used)<br />
+&#160; 130 - 82 - &amp;#8218; - baseline s. q<br />
+&#160; 131 - 83 - &amp;#402; - florin<br />
+&#160; 132 - 84 - &amp;#8222; - baseline d q<br />
+&#160; 133 - 85 - &amp;#8230; - ellipsis<br />
+&#160; 134 - 86 - &amp;#8224; - dagger<br />
+&#160; 135 - 87 - &amp;#8225; - d dagger<br />
+&#160; 136 - 88 - &amp;#710; - circumflex accent<br />
+&#160; 137 - 89 - &amp;#8240; - permile<br />
+&#160; 138 - 8a - &amp;#352; - S Hacek<br />
+&#160; 139 - 8b - &amp;#8249; - l s. guillemet<br />
+&#160; 140 - 8c - &amp;#338; - OE ligature<br />
+&#160; 141 - 8d - (removed) - (not used)<br />
+&#160; 142 - 8e - &amp;#381; - Z dieresis<br />
+&#160; 143 - 8f - (removed) - (not used)<br />
+&#160; 144 - 90 - (removed) - (not used)<br />
+&#160; 145 - 91 - &amp;#8216; - l s. q<br />
+&#160; 146 - 92 - &amp;#8217; - r s. q<br />
+&#160; 147 - 93 - &amp;#8220; - l d q<br />
+&#160; 148 - 94 - &amp;#8221; - r d q<br />
+&#160; 149 - 95 - &amp;#8226; - bullet<br />
+&#160; 150 - 96 - &amp;#8211; - en dash<br />
+&#160; 151 - 97 - &amp;#8212; - em dash<br />
+&#160; 152 - 98 - &amp;#732; - tilde accent<br />
+&#160; 153 - 99 - &amp;#8482; - trademark<br />
+&#160; 154 - 9a - &amp;#353; - s Hacek<br />
+&#160; 155 - 9b - &amp;#8250; - r s. guillemet<br />
+&#160; 156 - 9c - &amp;#339; - oe ligature<br />
+&#160; 157 - 9d - (removed) - (not used)<br />
+&#160; 158 - 9e - &amp;#382; - z dieresis<br />
+&#160; 159 - 9f - &amp;#376; - Y dieresis<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.5" id="s5.5"></a><span class="item-no">5.5</span>&#160; URL format
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; An <em>absolute</em>&#160;URL has a <span class="term">protocol</span>&#160;or <span class="term">scheme</span>, a <span class="term">network location</span>&#160;or <span class="term">hostname</span>, and, optional <span class="term">path</span>, <span class="term">parameters</span>, <span class="term">query</span>&#160;and <span class="term">fragment</span>&#160;segments. Thus, an absolute URL has this generic structure:<br />
+<br />
+
+<code class="code">&#160; &#160; (scheme) &#58; (//network location) /(path) ;(parameters) ?(query) #(fragment)</code>
+<br />
+<br />
+&#160; The schemes can only contain letters, digits, <span class="term">+</span>, <span class="term">.</span>&#160;and <span class="term">-</span>. Hostname is the portion after the <span class="term">//</span>&#160;and up to the first <span class="term">/</span>&#160;(if any; else, up to the end) when <span class="term">&#58;</span>&#160;is followed by a <span class="term">//</span>&#160;(e.g., <span class="term">abc.com</span>&#160;in <span class="term">ftp&#58;//abc.com/def</span>); otherwise, it consists of everything after the <span class="term">&#58;</span>&#160;(e.g., <span class="term">def@abc.com</span>&#160;in mailto:def@abc.com').<br />
+<br />
+&#160; <em>Relative</em>&#160;URLs do not have explicit schemes and network locations; such values are inherited from a <em>base</em>&#160;URL.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.6" id="s5.6"></a><span class="item-no">5.6</span>&#160; Brief on htmLawed code
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Much of the code's logic and reasoning can be understood from the documentation above.<br />
+<br />
+&#160; The <strong>output</strong>&#160;of htmLawed is a text string containing the processed input. There is no custom error tracking.<br />
+<br />
+&#160; <strong>Function arguments</strong>&#160;for htmLawed are:<br />
+<br />
+&#160; * &#160;<span class="term">$in</span>&#160;- first argument; a text string; the <strong>input text</strong>&#160;to be processed. Any extraneous slashes added by PHP when <em>magic quotes</em>&#160;are enabled should be removed beforehand using PHP's <span class="term">stripslashes()</span>&#160;function.<br />
+<br />
+&#160; * &#160;<span class="term">$config</span>&#160;- second argument; an associative array; optional; named <span class="term">$C</span>&#160;within htmLawed code. The array has keys with names like <span class="term">balance</span>&#160;and <span class="term">keep_bad</span>, and the values, which can be boolean, string, or array, depending on the key, are read to accordingly set the <strong>configurable parameters</strong>&#160;(indicated by the keys). All configurable parameters receive some default value if the value to be used is not specified by the user through <span class="term">$config</span>. <em>Finalized</em>&#160;<span class="term">$config</span>&#160;is thus a filtered and possibly larger array.<br />
+<br />
+&#160; * &#160;<span class="term">$spec</span>&#160;- third argument; a text string; optional. The string has rules, written in an htmLawed-designated format, <strong>specifying</strong>&#160;element-specific attribute and attribute value restrictions. Function <span class="term">hl_spec()</span>&#160;is used to convert the string to an associative-array, named <span class="term">$S</span>&#160;within htmLawed code, for internal use. <em>Finalized</em>&#160;<span class="term">$spec</span>&#160;is thus an array.<br />
+<br />
+&#160; <em>Finalized</em>&#160;<span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;are made <strong>global variables</strong>&#160;while htmLawed is at work. Values of any pre-existing global variables with same names are noted, and their values are restored after htmLawed finishes processing the input (to capture the <em>finalized</em>&#160;values, the <span class="term">show_settings</span>&#160;parameter of <span class="term">$config</span>&#160;should be used). Depending on <span class="term">$config</span>, another global variable <span class="term">hl_Ids</span>, to track <span class="term">id</span>&#160;attribute values for uniqueness, may be set. Unlike the other two variables, this one is not reset (or unset) post-processing.<br />
+<br />
+&#160; Except for the main <span class="term">htmLawed()</span>&#160;function, htmLawed's functions are <strong>name-spaced</strong>&#160;using the <span class="term">hl_</span>&#160;prefix. The <strong>functions</strong>&#160;and their roles are:<br />
+<br />
+&#160; * &#160;<span class="term">hl_attrval</span>&#160;- check attribute values against <span class="term">$spec</span><br />
+&#160; * &#160;<span class="term">hl_bal</span>&#160;- balance tags and ensure proper nesting<br />
+&#160; * &#160;<span class="term">hl_cmtcd</span>&#160;- handle CDATA sections and HTML comments<br />
+&#160; * &#160;<span class="term">hl_ent</span>&#160;- handle character entities<br />
+&#160; * &#160;<span class="term">hl_prot</span>&#160;- check a URL scheme/protocol<br />
+&#160; * &#160;<span class="term">hl_regex</span>&#160;- check syntax of a regular expression<br />
+&#160; * &#160;<span class="term">hl_spec</span>&#160;- convert user-supplied <span class="term">$spec</span>&#160;value to one used internally<br />
+&#160; * &#160;<span class="term">hl_tag</span>&#160;- handle element tags and attributes<br />
+&#160; * &#160;<span class="term">hl_tag2</span>&#160;- transform element tags<br />
+&#160; * &#160;<span class="term">hl_tidy</span>&#160;- compact/beautify HTML<br />
+&#160; * &#160;<span class="term">hl_version</span>&#160;- report htmLawed version<br />
+&#160; * &#160;<span class="term">htmLawed</span>&#160;- main function<br />
+<br />
+&#160; <span class="term">htmLawed()</span>&#160;finalizes <span class="term">$spec</span>&#160;(with the help of <span class="term">hl_spec()</span>) and <span class="term">$config</span>, and globalizes them. Finalization of <span class="term">$config</span>&#160;involves setting default values if an inappropriate or invalid one is supplied. This includes calling <span class="term">hl_regex()</span>&#160;to check well-formedness of regular expression patterns if such expressions are user-supplied through <span class="term">$config</span>. <span class="term">htmLawed()</span>&#160;then removes invalid characters like nulls and <span class="term">x01</span>&#160;and appropriately handles entities using <span class="term">hl_ent()</span>. HTML comments and CDATA sections are identified and treated as per <span class="term">$config</span>&#160;with the help of <span class="term">hl_cmtcd()</span>. When retained, the <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;characters identifying them, and the <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters inside them, are replaced with control characters (code-points <span class="term">1</span>&#160;to <span class="term">5</span>) till any tag balancing is completed.<br />
+<br />
+&#160; After this <em>initial processing</em>&#160;<span class="term">htmLawed()</span>&#160;identifies tags using regex and processes them with the help of <span class="term">hl_tag()</span>&#160;-- &#160;a large function that analyzes tag content, filtering it as per HTML standards, <span class="term">$config</span>&#160;and <span class="term">$spec</span>. Among other things, <span class="term">hl_tag()</span>&#160;transforms deprecated elements using <span class="term">hl_tag2()</span>, removes attributes from closing tags, checks attribute values as per <span class="term">$spec</span>&#160;rules using <span class="term">hl_attrval()</span>, and checks URL protocols using <span class="term">hl_prot()</span>. <span class="term">htmLawed()</span>&#160;performs tag balancing and nesting checks with a call to <span class="term">hl_bal()</span>, and optionally compacts/beautifies the output with proper white-spacing with a call to <span class="term">hl_tidy()</span>. The latter temporarily replaces white-space, and <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters inside <span class="term">pre</span>, <span class="term">script</span>&#160;and <span class="term">textarea</span>&#160;elements, and HTML comments and CDATA sections with control characters (code-points <span class="term">1</span>&#160;to <span class="term">5</span>, and <span class="term">7</span>).<br />
+<br />
+&#160; htmLawed permits the use of custom code or <strong>hook functions</strong>&#160;at two stages. The first, called inside <span class="term">htmLawed()</span>, allows the input text as well as the finalized <span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;values to be altered right after the initial processing (see <a href="#s3.7">section 3.7</a>). The second is called by <span class="term">hl_tag()</span>&#160;once the tag content is finalized (see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; The functionality of htmLawed is dictated by the external HTML standards. The code of htmLawed is thus written for a clear-cut aim, with not much concern for tweaking by other developers. The code is only minimally annotated with comments -- it is not meant to instruct. PHP developers familiar with the HTML specifications will see the logic, and others can always refer to the htmLawed documentation.
+</div>
+</div>
+<br />
+<hr /><br /><br /><span class="subtle"><small>HTM version of <em><a href="htmLawed_README.txt">htmLawed_README.txt</a></em> generated on 03 Sep, 2021 using <a href="http://www.bioinformatics.org/phplabware/internal_utilities">rTxt2htm</a> from PHP Labware</small></span>
+</div><!-- ended div body -->
+</div><!-- ended div top -->
+</body>
+</html>
\ No newline at end of file
index 08d5a0e5e8d06313b62e50ad1f008d5cee68bb22..60189d2ec8999a388f3468c3882169b67a313577 100755 (executable)
@@ -1,6 +1,6 @@
 /*
 /*
-htmLawed_README.txt, 25 May 2017
-htmLawed 1.2.2, 25 May 2017
+htmLawed_README.txt, 4 September 2021
+htmLawed 1.2.6, 4 September 2021
 Copyright Santosh Patnaik
 Dual licensed with LGPL 3 and GPL 2+
 A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed
 Copyright Santosh Patnaik
 Dual licensed with LGPL 3 and GPL 2+
 A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed
@@ -604,7 +604,7 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
 
   *  Named character entities must be properly cased. Thus, '&Lt;' or '&TILDE;' will not be recognized as entities and will be `neutralized`.
 
 
   *  Named character entities must be properly cased. Thus, '&Lt;' or '&TILDE;' will not be recognized as entities and will be `neutralized`.
 
-  *  HTML comments should not be inside element tags (they can be between tags), and should begin with '<!--' and end with '-->'. Characters like '<', '>', and '&' may be allowed inside depending on '$config', but any '-->' inside should be put in as '--&gt;'. Any '--' inside will be automatically converted to '-', and a space will be added before the comment delimiter '-->'.
+  *  HTML comments should not be inside element tags (they can be between tags), and should begin with '<!--' and end with '-->'. Characters like '<', '>', and '&' may be allowed inside depending on '$config', but any '-->' inside should be put in as '--&gt;'. Any '--' inside will be automatically converted to '-', and a space will be added before the '-->' comment-closing marker  unless '$config["comments"]' is set to '4' (section:- #3.3.1).
 
   *  'CDATA' sections should not be inside element tags, and can be in element content only if plain text is allowed for that element. They should begin with '<[CDATA[' and end with ']]>'. Characters like '<', '>', and '&' may be allowed inside depending on '$config', but any ']]>' inside should be put in as ']]&gt;'.
 
 
   *  'CDATA' sections should not be inside element tags, and can be in element content only if plain text is allowed for that element. They should begin with '<[CDATA[' and end with ']]>'. Characters like '<', '>', and '&' may be allowed inside depending on '$config', but any ']]>' inside should be put in as ']]&gt;'.
 
@@ -867,16 +867,16 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
 
   'CDATA' sections have the format '<![CDATA[...anything but not "]]>"...]]>', and HTML comments, '<!--...anything but not "-->"... -->'. Neither HTML comments nor 'CDATA' sections can reside inside tags. HTML comments can exist anywhere else, but 'CDATA' sections can exist only where plain text is allowed (e.g., immediately inside 'td' element content but not immediately inside 'tr' element content).
 
 
   'CDATA' sections have the format '<![CDATA[...anything but not "]]>"...]]>', and HTML comments, '<!--...anything but not "-->"... -->'. Neither HTML comments nor 'CDATA' sections can reside inside tags. HTML comments can exist anywhere else, but 'CDATA' sections can exist only where plain text is allowed (e.g., immediately inside 'td' element content but not immediately inside 'tr' element content).
 
-  htmLawed (function 'hl_cmtcd()') handles HTML comments or 'CDATA' sections depending on the values of '$config["comment"]' or '$config["cdata"]'. If '0', such markup is not looked for and the text is processed like plain text. If '1', it is removed completely. If '2', it is preserved but any '<', '>' and '&' inside are changed to entities. If '3', they are left as such.
+  htmLawed (function 'hl_cmtcd()') handles HTML comments or 'CDATA' sections depending on the values of '$config["comment"]' or '$config["cdata"]'. If '0', such markup is not looked for and the text is processed like plain text. If '1', it is removed completely. If '2', it is preserved but any '<', '>' and '&' inside are changed to entities. If '3' for '$config["cdata"]', or '3' or '4' for '$config["comment"]', they are left as such. When '$config["comment"]' is set to '4', htmLawed will not force a space character before the '-->' comment-closing marker. While such a space is required for standard-compliance, it can corrupt marker code put in HTML by some software (such as Microsoft Outlook).  
 
   Note that for the last two cases, HTML comments and 'CDATA' sections will always be removed from tag content (function 'hl_tag()').
 
   Examples:
 
   Input:
 
   Note that for the last two cases, HTML comments and 'CDATA' sections will always be removed from tag content (function 'hl_tag()').
 
   Examples:
 
   Input:
-    <!-- home link --><a href="home.htm"><![CDATA[x=&y]]>Home</a>
+    <!-- home link--><a href="home.htm"><![CDATA[x=&y]]>Home</a>
   Output ('$config["comment"] = 0, $config["cdata"] = 2'):
   Output ('$config["comment"] = 0, $config["cdata"] = 2'):
-    &lt;-- home link --&gt;<a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
+    &lt;-- home link--&gt;<a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
   Output ('$config["comment"] = 1, $config["cdata"] = 2'):
     <a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
   Output ('$config["comment"] = 2, $config["cdata"] = 2'):
   Output ('$config["comment"] = 1, $config["cdata"] = 2'):
     <a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
   Output ('$config["comment"] = 2, $config["cdata"] = 2'):
@@ -885,8 +885,10 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
     <!-- home link --><a href="home.htm">Home</a>
   Output ('$config["comment"] = 3, $config["cdata"] = 3'):
     <!-- home link --><a href="home.htm"><![CDATA[x=&y]]>Home</a>
     <!-- home link --><a href="home.htm">Home</a>
   Output ('$config["comment"] = 3, $config["cdata"] = 3'):
     <!-- home link --><a href="home.htm"><![CDATA[x=&y]]>Home</a>
-
-  For standard-compliance, comments are given the form '<!--comment -->', and any '--' in the content is made '-'.
+  Output ('$config["comment"] = 4, $config["cdata"] = 3'):
+    <!-- home link--><a href="home.htm"><![CDATA[x=&y]]>Home</a>
+    
+  For standard-compliance, comments are given the form '<!--comment -->', and any '--' in the content is made '-'. When '$config["comment"]' is set to '4', htmLawed will not force a space character before the '-->' comment-closing marker.
 
   When '$config["safe"] = 1', CDATA sections and comments are considered plain text unless '$config["comment"]' or '$config["cdata"]' is explicitly specified; see section:- #3.6.
 
 
   When '$config["safe"] = 1', CDATA sections and comments are considered plain text unless '$config["comment"]' or '$config["cdata"]' is explicitly specified; see section:- #3.6.
 
@@ -901,7 +903,7 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
   *  big - 'span style="font-size: larger;"'
   *  center - 'div style="text-align: center;"'
   *  dir - 'ul'
   *  big - 'span style="font-size: larger;"'
   *  center - 'div style="text-align: center;"'
   *  dir - 'ul'
-  *  font (face, size, color) -        'span style="font-family: ; font-size: ; color: ;"' (size transformation reference:- http://style.cleverchimp.com/font_size_intervals/altintervals.html)
+  *  font (face, size, color) -        'span style="font-family: ; font-size: ; color: ;"' (size transformation reference:- http://web.archive.org/web/20180201141931/http://style.cleverchimp.com/font_size_intervals/altintervals.html)
   *  isindex - based on '$config["make_tag_strict"]', unchanged ('1') or removed ('2')
   *  s - 'span style="text-decoration: line-through;"'
   *  strike - 'span style="text-decoration: line-through;"'
   *  isindex - based on '$config["make_tag_strict"]', unchanged ('1') or removed ('2')
   *  s - 'span style="text-decoration: line-through;"'
   *  strike - 'span style="text-decoration: line-through;"'
@@ -918,7 +920,7 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
   The output:
 
     <div style="text-align: center;">
   The output:
 
     <div style="text-align: center;">
-     The PHP <span style="text-decoration: line-through;">software</span> script used for this <span style="text-decoration: line-through;">web-page</span> web-page is <span style="font-weight: bold; font-family: arial; color: red; font-size: 200%;">htmLawedTest.php</span>, from <span style="color:green; text-decoration: underline;">PHP Labware</span>.
+     The PHP <span style="text-decoration: line-through;">software</span> script used for this <span style="text-decoration: line-through;">web-page</span> web-page is <span style="font-weight: bold; font-size: 200%; color: red; font-family: arial;">htmLawedTest.php</span>, from <u style="color:green">PHP Labware</u>.
     </div>
 
 
     </div>
 
 
@@ -1025,7 +1027,7 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
 
   Note that attributes specified in '$config["deny_attribute"]' are denied globally, for all elements. To deny attributes for only specific elements, '$spec' (see section:- #2.3) can be used. '$spec' can also be used to element-specifically permit an attribute otherwise denied through '$config["deny_attribute"]'.
   
 
   Note that attributes specified in '$config["deny_attribute"]' are denied globally, for all elements. To deny attributes for only specific elements, '$spec' (see section:- #2.3) can be used. '$spec' can also be used to element-specifically permit an attribute otherwise denied through '$config["deny_attribute"]'.
   
-  Finer restrictions on attributes can also be put into effect through '$config["deny_attribute"]' (section:- 3.4.9).
+  Finer restrictions on attributes can also be put into effect through '$config["hook_tag"]' (section:- #3.4.9).
 
   *Note*: To deny all but a few attributes globally, a simpler way to specify '$config["deny_attribute"]' would be to use the notation '* -attribute1 -attribute2 ...'. Thus, a value of '* -title -href' implies that except 'href' and 'title' (where allowed as per standards) all other attributes are to be removed. With this notation, the value for the parameter 'safe' (section:- #3.6) will have no effect on 'deny_attribute'. Values of 'aria*' 'data*', and 'on*' cannot be used in this notation to refer to the sets of all ARIA, data-*, and on* attributes respectively.
 
 
   *Note*: To deny all but a few attributes globally, a simpler way to specify '$config["deny_attribute"]' would be to use the notation '* -attribute1 -attribute2 ...'. Thus, a value of '* -title -href' implies that except 'href' and 'title' (where allowed as per standards) all other attributes are to be removed. With this notation, the value for the parameter 'safe' (section:- #3.6) will have no effect on 'deny_attribute'. Values of 'aria*' 'data*', and 'on*' cannot be used in this notation to refer to the sets of all ARIA, data-*, and on* attributes respectively.
 
@@ -1257,7 +1259,7 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
 
       // Inject param for allowscriptaccess
       if($element == 'object'){
 
       // Inject param for allowscriptaccess
       if($element == 'object'){
-        $new_element = '<param id='my_'. $id; allowscriptaccess="never" />';
+        $new_element = '<param id="my_'. $id. '"; allowscriptaccess="never" />';
         ++$id;
       }
 
         ++$id;
       }
 
@@ -1367,6 +1369,18 @@ A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/intern
   (The release date for the downloadable package of files containing documentation, demo script, test-cases, etc., besides the 'htmLawed.php' file, may be updated without a change-log entry if the secondary files, but not htmLawed per se, are revised.)
 
   `Version number - Release date. Notes`
   (The release date for the downloadable package of files containing documentation, demo script, test-cases, etc., besides the 'htmLawed.php' file, may be updated without a change-log entry if the secondary files, but not htmLawed per se, are revised.)
 
   `Version number - Release date. Notes`
+
+  1.2.6 - 4 September 2021. Fixes a bug that arises when '$config["deny_attribute"]' has a 'data-*' attribute with > 1 hyphen character 
+
+  1.2.5 - 24 September 2019. Fixes two bugs in 'font' tag transformation
+
+  1.2.4.2 - 16 May 2019. Corrects a PHP notice if a semi-colon is present in '$config["schemes"]' 
+
+  1.2.4.1 - 12 September 2017. Corrects a function re-declaration bug introduced in version 1.2.4
+    
+  1.2.4 - 31 August 2017. Removes use of PHP 'create_function' function and '$php_errormsg' reserved variable (deprecated in PHP 7.2)
+  
+  1.2.3 - 5 July 2017. New option value of '4' for '$config["comments"]' to stop enforcing a space character before the '-->' comment-closing marker
   
   1.2.2 - 25 May 2017. Fix for a bug in parsing '$spec' that got introduced in version 1.2; also, '$spec' is now parsed to accommodate specifications for an HTML element when they are specified in multiple rules
   
   
   1.2.2 - 25 May 2017. Fix for a bug in parsing '$spec' that got introduced in version 1.2; also, '$spec' is now parsed to accommodate specifications for an HTML element when they are specified in multiple rules
   
diff --git a/web/libraries/htmLawed/htmLawed_TESTCASE.txt b/web/libraries/htmLawed/htmLawed_TESTCASE.txt
new file mode 100755 (executable)
index 0000000..24b00e7
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+htmLawed_TESTCASE.txt, 24 September 2019
+To test htmLawed
+Copyright Santosh Patnaik
+Dual licensed with LGPL 3 and GPL 2+
+A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed
+*/
+
+This file has UTF-8-encoded text with both correct and incorrect/malformed HTML/XHTML code snippets to test htmLawed (test cases/samples). The entire text may also be used as a unit.
+
+************************************************
+when viewing this file in a web browser, set the
+character encoding to Unicode/UTF-8
+************************************************
+
+--------------------- start --------------------
+
+<em>Try different $config and $spec values. Some text even when filtered in will not be displayed in a rendered web-page</em><br />
+
+<h6>Attributes</h6>
+
+<strong>Xml:lang:</strong><a lang="en" xml:lang="en"></a>, <a lang="en"></a>, <a xml:lang="en"></a><br />
+<strong>Standard, predefined value, or empty attribute:</strong> <input type="text" disabled />, <input type="text" disabled="DISABLED" />, <input type="text" disabled="1" /><br />
+<strong>Required:</strong> <img />, <img alt="image" /><br />
+<strong>Quote & space variation:</strong> <a id=id1 name=xy>a</a>, <a id='id2' name="xy">a</a>, <a   id=' id3 ' name = "n"  >a</a><br />
+<strong>Invalid:</strong> <a id="id4" src="s">a</a><br />
+<strong>Duplicated:</strong> <a id="id5" id="id6">a</a><br />
+<strong>Deprecated:</strong> <a id="id7" target="self" name="n">a</a>, <hr noshade="noshade" /><br />
+<strong>Casing:</strong> <a HREF=""></a><br />
+<strong>Custom:</strong> <img alt="image" my:data="portrait" /><br />
+<strong>Data-*:</strong> <a data-xml="x" data-xmnt="x" data-xmlnt="x" data-xmn:t="x" data-12="x"  data-רש="x" data-xmxm="x">a</a><br />
+<strong>Admin-restricted?:</strong> <a href="x" onclick="alert();"></a>
+
+<h6>Attribute values</h6>
+
+<strong>Duplicate ID value:</strong><a id="id8"></a>, <a id="my_id8"></a>, <a id="id8"></a><br />
+(try 'my_' for prefix)<br />
+<strong>Double-quotes in value:</strong><a title=ab"c"></a>, <a title="ab"c"></a>, <a title='ab"c'></a><br />
+(try filter for CSS expression)<br />
+<strong>CSS expression</strong>: <div style="prop:expression();"></div><div style="prop:expression()"></div><div style="prop: expression();"></div><div style="prop : expression()"></div><div style="prop:expression(js);"></div><div style="prop:expression(js;)"></div><div style="prop: expression('js');"></div><div style="prop : expr ession('js':)"></div><div style="prop&#x3a;expression( 'js&#x40; );"></div><br />
+<strong>Other:</strong> <input size="50" class="my" value="an input an input an input" />, <input size="5" class="your" value="an input" /><br />
+(try 'maxlen', 'maxval', etc., for 'input' in '$spec')
+
+<h6>Blockquotes</h6>
+
+<blockquote>abc</blockquote><br />
+<blockquote>abc<div>def</div></blockquote><br />
+<blockquote><div>abc</div>def</blockquote><br />
+<blockquote>abc<div>def</div>ghi</blockquote><br />
+abc<div>def</div>ghi<br />
+<blockquote>QQQ<div>x</div><!-- comment --></blockquote><br />
+<blockquote><div>x</div><!-- comment -->QQQ</blockquote><br />
+<blockquote><!-- comment --><div>x</div>QQQ<div>x</div></blockquote><br />
+<blockquote><div>x<!-- comment --></div>QQQ</blockquote><p>x</p><br />
+<br />
+(try with blockquote parent)
+
+<h6>CDATA sections</h6>
+
+<strong>Special characters inside:</strong> <![CDATA[ ]]> ]]>, <![CDATA[ 3 < 4 > 3.5, & 4 &gt; 4 ]]><br />
+<strong>Normal:</strong> <![CDATA[ check ]]>, <em>CDATA follows:<![CDATA[ check ]]></em><br />
+<strong>Malformed:</strong> <![cdata check ]]>, < ![CDATA check ]]>, <![CDATA check ]]>, < ![CDATA check ] ]><br />
+<strong>Invalid:</strong> <em <![CDATA[ check ]]>>CDATA in tag content</em>, <table><![CDATA[ check ]]><tr><td>text not allowed</td></tr></table>
+
+<h6>Complex-1: deprecated elements</h6>
+
+<center>
+The PHP <s>software</s> script used for this <strike>web-page</strike> webpage is <font style="font-weight: bold " face=arial size='+3' color   =  "red  ">htmLawedTest.php</font>, from <u style= 'color:green'>PHP Labware</u>.
+</center>
+
+<h6>Complex-2: deprecated attributes</h6>
+
+<img src="s" alt="a" name="n" /><img src="s" alt="a" id="id9" name="n" />
+<br clear="left" />
+<hr noshade size="1" />
+<img name="id10" src="s" align="left" alt="image" hspace="10" vspace="10" width="10em" height="20" border="1" style="padding:5px;" />
+<table width="50em" align="center" bgcolor="red">
+     <tr>
+      <td width="20%">
+       <div align="center">
+        <h3 align="right">Section</h3>
+        <p align="right">Para</p>
+        <ol type="a" start="e"><li value="x"><a name="x">First</a> <a name="x" id="id11">item</a></li></ol>
+       </div>
+      </td>
+      <td width="*">
+       <ol type="1"><li>First item</li></ol>
+      </td>
+     </tr>
+    </table>
+<br clear="all" />
+
+<h6>Complex-3: embed, object, area</h6>
+
+<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/ls7gi1VwdIQ"></param><embed src="http://www.youtube.com/v/ls7gi1VwdIQ" type="application/x-shockwave-flash" width="425" height="350"></embed></object><br />
+
+<embed src="http://www.youtube.com/v/ls7gi1VwdIQ" type="application/x-shockwave-flash" width="425" height="350"></embed><br />
+
+<object data="1.gif" type="image/gif" usemap="#map1"><map name="map1">
+<p>navigate the site: <a href="1" shape="REct" coOrds="0,0,118,28">1</a> | <a href="3" shape="circle" coords="184,200,60">3</a> | <a href="4" shape="poly" coords="276,0,276,28,100,200,50,50,276,0">4</a></p>
+<area href="5" shape="Rect" coords="0,0,118,28">
+</map></object>
+
+<param name="name">value</param>
+
+<object id="obj1">
+   <param name="param1">
+   <object id="obj2">
+      <param name="param2">
+   </object>
+</object>
+
+<h6>Complex-4: nested and other tables</h6>
+
+<table border="1" bgcolor="red"> <tr> <td> Cell </td> <td colspan="2" rowspan="2"> <table border="1" bgcolor="green"> <tr> <td> Cell </td> <td colspan="2" rowspan="2"> </td> </tr> <tr> <td> Cell </td> </tr> <tr> <td> Cell </td> <td> Cell </td> <td> Cell </td> </tr> </table> </td> </tr> <tr> <td> Cell </td> </tr> <tr> <td> Cell </td> <td> Cell </td> <td> Cell </td> </tr> </table><br />
+<strong>PCDATA wrong:</strong> <table>Well<caption>Hello</caption></table><br />
+<strong>Missing tr:</strong> <table><td>Well</td></table><br />
+
+<h6>Complex-5: pseudo, disallowed or non-HTML tags</h6>
+
+(Try different 'keep_bad' values)
+<*> Pseudotags <*>
+<xml>Non-HTML tag xml</xml>
+<p>
+Disallowed tag p
+</p>
+<ul>Bad<li>OK</li></ul>
+
+<h6>Elements</h6>
+
+<strong>Unbalanced:</strong> <a href="h"><em>check</a></em><br />
+<strong>Non-XHTML:</strong> <div><center><dir></dir></center></div><br />
+<strong>Malformed:</strong> < a href=""></a>, <a href=""  ></a>, <a href=""     ></a>, <a href=""
+></a>, <a href="">< /a>, < a href=""></a >, <img src="s" alt="a"   />, <img src="s" alt="a"/ >, <imgsrc="s" alt="a" /><br />
+<strong>Invalid:</strong> <image src="s" alt="a" /><br />
+<strong>Empty:</strong> <img src="s" alt="a" />, <img src="s" alt="a"></img>, <img src="s" alt="a">text</img><br />
+<strong>Content invalid:</strong> <a href="h">1<a>2</a></a><br />
+<strong>Content invalid?:</strong> <form></form><br /> (try setting 'form' as parent)<br />
+<strong>Casing:</strong> <A href=""></a><br />
+<strong>Check for tidy:</strong> <br /><hr /></div><hr /></div><hr /></div><div>hi</div>
+
+<h6>Entities</h6>
+
+<strong>Special:</strong> &amp; 3 < 2 & 5>4 and j >i >a & i<j>a<br />
+<strong>Padding:</strong> &#00066; &#066; &#x00066; &#x066; &#x003; &#0003;<br />
+<strong>Malformed:</strong> & #x27;, &x27;, &#x27; &TILDE;, &tilde<br />
+<strong>Invalid:</strong> &#x3;, &#55296;, &#03;, &#1114112;, &#xffff, &bad;<br />
+<strong>Discouraged characters:</strong> &#x7f;, &#132;, &#64992;, &#1114110;<br />
+<strong>Context:</strong> '&gt;', &lt;?<br />
+<strong>Casing:</strong> &#X27;, &#x27;, &TILDE;, &tilde;
+<br />
+(also check named-to-numeric and hexdec-to-decimal, and vice versa, conversions)
+
+<h6>Format</h6>
+
+<strong>Valid but ill-formatted:</strong> text <!-- comment -->
+text <!--
+A   c  o  m  m  e  n  t -->
+<script>
+       <![CDATA[
+               code
+       ]]>
+</script><!-- comment --><![CDATA[ cdata ]]> <a>text</b> text<pre id="none">p r e</pre>
+<textarea>text</textarea>        <textarea>
+         text  text  
+</textarea>            text  text <br /><hr />
+text <img src="none" alt="none" /> t<em class="none">e<strong>x</strong>t</em>
+text <img src="none" alt="none" />     <b>t<em> e <strong> x </strong> t</em></b>
+       <a href="a">    text <img src="none" alt="none" />      <b>t <em> e <strong> x </strong> t</em></b>
+       </a>
+<span style="background-color: yellow;">text <img src="none" alt="none" />     <b> <em> t e <strong> x </strong> t</em></b></span>
+<script>script</script>
+<div>
+       <pre id="none">p <a>r</a> e <!-- comment --> </pre>
+               <pre>
+                               pre
+               </pre>
+</div>
+<div><div><table border="1" style="background-color: red;"><tr><td>Cell</td><td colspan="2" rowspan="2"><table border="1" style="background-color: green;"><tr><td>Cell</td><td colspan="2" rowspan="2"></td></tr><tr><td>Cell</td></tr><tr><td>Cell</td><td>Cell</td><td>Cell</td></tr></table></td></tr><tr><td>Cell</td></tr><tr><td>Cell</td><td>Cell</td><td>Cell</td></tr></table></div></div>
+(try to compact or beautify)
+
+<h6>Forms</h6>
+
+(note nesting of 'form', missing required attributes, etc.)<br />
+<form>
+<script type="text/javascript">s</script>
+<fieldset><legend>p</legend>l <input name="personal_lastname" type="text" tabindex="1"></fieldset>
+<input name="h" type="checkbox" value="h" tabindex="20"> h
+<textarea name="t">t</textarea>
+<form action="a" method="get"></form></form><br />
+<form action="b" method="get"><p><input type="text" value="i" /></form><br />
+<form>B:<input type="text" value="b" />C:<input type="text" value="c" /></form><br />
+(try each of these lines separately)<br />
+<form action="a">what<br />
+<form action="a">what
+(try with container as div and as form)<br />
+<form>c <a>a</a> <b>b</b><input /><script>s</script>
+
+<h6>HTML comments (also CDATA)</h6>
+
+<strong>Script inside:</strong> <!--[if gte IE 4]>
+<SCRIPT>alert('XSS');</SCRIPT>
+<![endif]--><br />
+<strong>Special characters inside: <!-- <![CDATA check ]]> -->, <!-- 3 < 4 > 3.5, & 4 &gt; 4 -->, <!-- che--ck -->, <!--[if !IE]> <--><a>c</a><!--> <![endif]--><br />
+<strong>Normal:</strong> <!-- check -->, <!--check -->, <em>comment:<!-- check --></em><!-- check -->, <table><!-- check --><tr><td>text not allowed</td></tr></table><br />
+<strong>Malformed:</strong> <![cdata check ]]>, < ![CDATA check ]]>, < ![CDATA check ] ]><br />
+Invalid:</strong> <em <!-- check -->>comment in tag content</em>, <!--check-->
+
+<h6>HTML5</h6>
+
+<strong>figure and figcaption:</strong> <figure><img src="picture.jpg" alt="picture"><figcaption>Caption for the awesome picture</figcaption></figure>
+<strong>article:</strong> <h1>A</h1><p>B</p><article><h2>C</h2></article><article><h2>E</h2><p>F</p><p>G</p></article>
+<strong>meter</strong>: <p>Heat <meter min="100" max="200" value="150">150</meter>.</p>
+<strong>datalist</strong>: <input list="b" /><datalist id="b"><option value="c"><option value="d"></datalist>
+
+<h6>Ins-Del</h6>
+
+(depending on context, these elements can be of either block or inline type)<br />
+<p><ins datetime="d" cite="c"><div>block</div></ins></p><br />
+<p><del>d</del></p><br />
+<p><ins><del>d</del></ins></p><div><ins><p><del><div>d</div></del></p></ins></div><ins><div>d</div></ins>
+
+<h6>Lists</h6>
+
+<strong>Invalid character data</strong>: <ul><li>(item</li>)</ul><br />
+<strong>Definition list</strong>: <dl><dt>a</dt>bad<dd>first <em>one</em></dd><dt>b</dt><dd>second</dd></dl><br />
+<strong>Definition list, close-tags omitted</strong>: <dl><dt>a</dt>bad<dd>first <em>one</em></dd><dt>b<dd>second</dl><br />
+<strong>Definition lists, nested</strong>: <dl>
+ <dt>T1</dt>
+ <dd>D1</dd>
+ <dt>T2</dt>
+ <dd>D2<dl><dt>t1</dt><dd>d1</dd><dt>t2</dt><dd>d2</dd></dl></dd>
+ <dt>T3</dt>
+ <dd>D3</dd>
+ <dt>T4</dt>
+ <dd>D4<dl><dt>t1</dt><dd>d1</dd></dl></dd>
+</dl><br />
+<strong>Definition lists, nested, close-tags omitted</strong>: <dl>
+ <dt>T1
+ <dd>D1</dd>
+ <dt>T2</dt>
+ <dd>D2<dl><dt>t1<dd>d1<dt>t2</dt><dd>d2</dd></dl></dd>
+ <dt>T3
+ <dd>D3
+ <dt>T4
+ <dd>D4<dl><dt>t1<dd>d1</dl></dd>
+</dl><br />
+<strong>Nested</strong>: <ul>
+ <li>l1</li>
+ <li>l2<ol><li>lo1</li><li>lo2</li></ol></li>
+ <li>l3</li>
+ <li>l4<ol><li>lo3</li><li>lo4<ol><li>lo5</li></ol></li></ol></li>
+</ul><br />
+<strong>Nested, directly</strong>: <ul>
+ <li>l1</li>
+ <ol>l2</ol>
+ <li>l3</li>
+</ul><br />
+<strong>Nested, close-tags omitted</strong>: <ul>
+ <li>l1</li>
+ <li>l2<ol><li>lo1<li>lo2</ol>
+ <li>l3
+ <li>l4<ol><li>lo3<li>lo4<ol><li>lo5</ol></ol>
+</ul><br />
+<strong>Complex</strong>:
+<ol><script></script><li><table><tr><td>
+<ul><li id="search" class="widget widget_search">                      <form id="searchform" method="get" action="http://kohei.us">
+                       <div>
+
+                       <input type="text" name="s" id="s" size="15" /><br />
+                       <input type="submit" value="Search" />
+                       </div>
+                       </form>
+               </li></ul>
+</td></tr></table></li></ol>
+<strong>Menu</strong>: <menu type="toolbar"><li><menu label="File">
+      <button type="button" onclick="new()">New...</button>
+    </menu></li><li><menu label="Edit"><button type="button" onclick="cut()">Cut...</button></menu></li>
+    </menu>
+
+<h6>Microdata</h6>
+
+<div itemscope itemtype="http://data-vocabulary.org/Person"> 
+I am <span itemprop="name">X</span> but people call me <span itemprop="nickname">Y</span>. 
+Find me at <a href="http://www.xy.com" itemprop="url">www.xy.com</a>
+</div>
+
+<h6>Microsoft Word</h6>
+
+<strong>Proprietary tag</strong>: <p class=3DMsoNormal><o:p>&nbsp;</o:p></p><br />
+<strong>XML declaration</strong>: <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><br />
+<strong>XML-invalid character code-point (may not replicate)</strong>: <p class=3DMsoNormal>“Where is he?” asked both Mary – the one so lovely – and Jane.</p>
+
+<h6>Nesting</h6>
+
+<strong>Block or inline a</strong>: <p><a href="link">text</a></p><a href="link"><div>hi</div></a><br />
+
+<h6>Non-English text-1</h6>
+
+Inscrieţi-vă acum la a Zecea Conferinţă Internaţională<br />
+გთხოვთ ახლავე გაიაროთ რეგისტრაცია<br />
+večjezično računalništvo<br />
+<a title="อ.อ่าง">อ.อ่าง</a><br />
+<a title="הירשמו
+כעת לכנס ">Зарегистрируйтесь сейчас
+на Десятую Международную Конференцию по</a><br />
+(this file should have utf-8 encoding; some characters may not be displayed because of missing fonts, etc.)
+
+<h6>Non-English text-2: entities</h6>
+
+&#29992;&#32479;&#19968;&#30721;<br />
+&#4306;&#4311;&#4334;&#4317;&#4309;&#4311;<br />
+Inscreva-se agora para a D&#233;cima Confer&#234;ncia Internacional Sobre O Unicode, realizada entre os dias 10 e 12 de mar&#231;o de 1997 em Mainz
+na Alemanha.
+
+<h6>Ruby</h6>
+
+(need compatible browser)<br />
+<ruby xml:lang="ja">
+  <rbc>
+    <rb>斎</rb>
+    <rb>藤</rb>
+    <rb>信</rb>
+    <rb>男</rb>
+  </rbc>
+  <rtc class="reading">
+    <rt>さい</rt>
+    <rt>とう</rt>
+    <rt>のぶ</rt>
+    <rt>お</rt>
+  </rtc>
+  <rtc class="annotation">
+    <rt rbspan="4" xml:lang="en">W3C Associate Chairman</rt>
+  </rtc>
+</ruby><br />
+<ruby>
+  <rb>WWW</rb>
+  <rp>(</rp><rt>World Wide Web</rt><rp>)</rp>
+</ruby><br />
+<ruby>
+  A
+  <rp>(</rp><rt>aaa</rt><rp>)</rp>
+</ruby>
+
+
+<h6>Tables</h6>
+
+<strong>Omitted closing tags:</strong> <table>
+<colgroup><col style="x" /><col style="y" />
+<thead>
+<tr><th>h1c1<th>h1c2
+<tbody>
+<tr><td>r1c1<td>r1c2
+<tr><td>r2c1<td>r2c2
+</table><br />
+<strong>Nested, omitted closing tags:</strong> <table>
+<colgroup><col style="x" /><col style="y" />
+<thead>
+<tr><th>h1c1<th>h1c2
+<tbody>
+<tr><td>r1c1<td>r1c2<table>
+<colgroup><col style="x" /><col style="y" />
+<thead>
+<tr><th>h1c1<th>h1c2
+<tbody>
+<tr><td>r1c1<td>r1c2
+<tr><td>r2c1<td>r2c2
+</table>
+<tr><td>r2c1<td>r2c2
+</table><br />
+
+<h6>Tag transformation</h6>
+<strong>Font element with malicious code:</strong> <p><font color="z-index:123;width:100%;height:100%;position:fixed;top:0;left:0;background-size:cover;background-attachment:fixed;background-image:url(https://i.imgur.com/VQ30s65.png)"></font></p><br />
+<strong>Font element intended as 'inline' element:</strong> <p><font color='red'>hi</font></p><br />
+<strong>Font element intended as 'block' element:</strong> <div><font color='red'><div>hi</div></font></div><br />
+<strong>Font element intended as 'block' element:</strong> <center><font color='red' face="serif, 'Times'"><div>hi</div><div>QQQ</div></font></center><br />
+
+<h6>Tidy</h6>
+<strong>White-space handling:</strong> abc<em> def </em> ghi   abc <em>def</em> ghi
+
+<h6>URLs</h6>
+
+<strong>Relative and absolute:</strong> <a href="mailto:x"></a>, <a href="http://a.com/b/c/d.f"></a>, <a href="./../d.f"></a>, <a href="./d.f"></a>, <a href="d.f"></a>, <a href="#s"></a>, <a href="./../../d.f#s"></a><br />
+(try base URL value of 'http://a.com/b/')<br />
+<strong>CSS URLs:</strong> <div style="background-image: url('a.gif');"></div>, <div style="background-image: URL(&quot;a.gif&quot;);"></div>, <div style="background-image: url('http://a.com/a.gif');"></div>, <div style="background-image: url('./../a.gif');"></div>, <div style="background-image: &#117;r&#x6C;('js&#58;xss'&#x29;"></div><br />
+<strong>Double URLs:</strong> <a style="behaviour: url(foo) url(http://example.com/xss.htc)">b</a><br />
+<strong>Anti-spam:</strong> (try regex for 'http://a.com', etc.) <a href="mailto:x@y.com"></a>, <a href="http://a.com/b@d.f"></a>, <a href="a.com/d.f" rel="nofollow"></a>, <a href="a.com/d.f" rel="1, 2"></a>, <a href="a.com/d.f"></a>, <a href="b.com/d.f"></a>, <a href="c.com/d.f">, <a href="denied:http://c.com/d.f"></a><br />
+<strong>Soft-hyphen:</strong> <a href="http://q=ídis­c">ídis­c</a>
+
+<h6>XSS</h6>
+
+<img alt="<img onmouseover=confirm(1)//"<"">
+'';!--"<xss>=&{()}<br />
+<img src="javascript%3Aalert('xss');" /><br />
+<img src="javascript:alert('xss');" /><br />
+<img src="java script:alert('xss');" /><br />
+<img
+src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41; /><br />
+<font color='#FF6699"onmouseover="alert(1)//'>test</font>
+<font color='<img//onerror="alert`www.ptsecurity.com`"src=Psych0tr1a'>
+<div style="javascript:alert('xss');"></div><br />
+<div style="background-image:url(javascript:alert('xss'));"></div><br />
+<div style="background-image:url(&quot;javascript:alert('xss')&quot; );"></div><br />
+<!--[if gte IE 4]><script>alert('xss');</script><![endif]--><br />
+<script a=">" src="http://ha.ckers.org/xss.js"></script><br />
+<div style="background-image: &#117;r&#x6C;('js&#58;xss'&#x29;"></div><br />
+<a style=";-moz-binding:url(http://lukasz.pilorz.net/xss/xss.xml#xss)" href="http://example.com">test</a><br />
+<strong>Bad IE7:</strong> <a href="http://x&x=%22+style%3d%22background-image%3a+expression%28alert
+%28%27xss%3f%29%29">x</a><br />
+<strong>Opera:</strong> <a href="\xE2\x80\x83javascript:alert(123)">link</a>
+<strong>Bad IE7:</strong> <a style=color:expr/*comment*/ession(alert(document.domain))>xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp&#x72;ession(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: &#101;xpression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: %45xpression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/**/expression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/**/&#69;xpression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/**/Exp&#x72;ession(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: expr%45ssion(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp/* */ression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp /* */ression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp/ * * /ression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/* x */expression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/* */ */expression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="width: /****/**;;;;;;*/expression/**/(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="padding:10px; background:/**/expression(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="background: huh /* */ */expression(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="background:/**/expression(alert('xss'));background:/**/expression(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> exp/*<a style='no\xss:noxss("*//*");xss:&#101;x&#x2F;*XSS*//*/*/pression(alert("XSS"))'>x</a><br />
+<strong>Bad IE7:</strong> <a style="background:&#69;xpre\ssion(alert('xss'));">hi</a><br />
+<strong>Bad IE7:</strong> <a style="background:expre&#x5c;ssion(alert('xss'));">hi</a><br />
+<strong>Bad IE7:</strong> <a style="color: \0065 \0078 \0070 \0072 \0065 \0073 \0073 \0069 \006f \006e \0028 \0061 \006c \0065 \0072 \0074 \0028 \0031 \0029 \0029">test</a><br />
+<strong>Bad IE7:</strong> <a style="xss:e&#92;&#48;&#48;&#55;&#56;pression(window.x?0:(alert(/XSS/),window.x=1));">hi</a><br />
+<strong>Bad IE7:</strong> <a style="background:url('java
+script:eval(document.all.mycode.expr)')">hi</a><br />
+
+<h6>Other</h6>
+
+3 < 4 <br />
+3 > 4 <br />
+  > 3 <br />
+<._.> hi! <br />
+<<< ALERT >>> <br />
+<![if !vml]> some stuff <![endif]> <br />
+<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> <br />
+<uml:ns ns = "urn:www"> <br />
+<uml:ns ns = 'urn:www'> <br />
+if(13<age AND 21>age){say 'teen'} <br />
+age >51 and a smoking history of >51 pack-years <b>was</b> <br />
+age > 51 and a smoking history of >51 pack-years <b>was</b> <br />
+age <51 and a smoking history of <51 pack-years <b>was</b> <br />
+age < 51 and a smoking history of < 51 pack-years <b>was</b> <br />
+<b>age >51 and a smoking history of >51 pack-years</b> <br />
+<b>age > 51 and a smoking history of >51 pack-years</b> <br />
+<b>age <51 and a smoking history of <51 pack-years</b> <br />
+<b>age < 51 and a smoking history of < 51 pack-years</b> <br />
index 7b05dd871bbcea785fc9f3d4d55eca6c2a7e6364..b384d9819068f25c8c08720cc755e9f765b3c132 100755 (executable)
@@ -1,7 +1,7 @@
 <?php
 
 /*
 <?php
 
 /*
-htmLawed 1.2.4.1, 12 September 2017
+htmLawed 1.2.5, 24 September 2019
 Copyright Santosh Patnaik
 Dual licensed with LGPL 3 and GPL 2+
 A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed
 Copyright Santosh Patnaik
 Dual licensed with LGPL 3 and GPL 2+
 A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed
@@ -43,7 +43,7 @@ $C['deny_attribute'] = $x;
 // config URLs
 $x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet'. (empty($C['safe']) ? ', app, javascript; *: data, javascript, ' : '; *:'). 'file, http, https';
 $C['schemes'] = array();
 // config URLs
 $x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet'. (empty($C['safe']) ? ', app, javascript; *: data, javascript, ' : '; *:'). 'file, http, https';
 $C['schemes'] = array();
-foreach(explode(';', str_replace(array(' ', "\t", "\r", "\n"), '', $x)) as $v){
+foreach(explode(';', trim(str_replace(array(' ', "\t", "\r", "\n"), '', $x), ';')) as $v){
  $x = $x2 = null; list($x, $x2) = explode(':', $v, 2);
  if($x2){$C['schemes'][$x] = array_flip(explode(',', $x2));}
 }
  $x = $x2 = null; list($x, $x2) = explode(':', $v, 2);
  if($x2){$C['schemes'][$x] = array_flip(explode(',', $x2));}
 }
@@ -652,11 +652,11 @@ if($e == 'font'){
  $a2 = '';
  while(preg_match('`(^|\s)(color|size)\s*=\s*(\'|")?(.+?)(\\3|\s|$)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
  $a2 = '';
  while(preg_match('`(^|\s)(color|size)\s*=\s*(\'|")?(.+?)(\\3|\s|$)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
-  $a2 .= strtolower($m[2]) == 'color' ? (' color: '. str_replace('"', '\'', trim($m[4])). ';') : (isset($fs[($m = trim($m[4]))]) ? ($a2 .= ' font-size: '. str_replace('"', '\'', $fs[$m]). ';') : '');
+  $a2 .= strtolower($m[2]) == 'color' ? (' color: '. str_replace(array('"', ';', ':'), '\'', trim($m[4])). ';') : (isset($fs[($m = trim($m[4]))]) ? (' font-size: '. $fs[$m]. ';') : '');
  }
  while(preg_match('`(^|\s)face\s*=\s*(\'|")?([^=]+?)\\2`i', $a, $m) or preg_match('`(^|\s)face\s*=(\s*)(\S+)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
  }
  while(preg_match('`(^|\s)face\s*=\s*(\'|")?([^=]+?)\\2`i', $a, $m) or preg_match('`(^|\s)face\s*=(\s*)(\S+)`i', $a, $m)){
   $a = str_replace($m[0], ' ', $a);
-  $a2 .= ' font-family: '. str_replace('"', '\'', trim($m[3])). ';';
+  $a2 .= ' font-family: '. str_replace(array('"', ';', ':'), '\'', trim($m[3])). ';';
  }
  $e = 'span'; return ltrim(str_replace('<', '', $a2));
 }
  }
  $e = 'span'; return ltrim(str_replace('<', '', $a2));
 }
@@ -725,5 +725,5 @@ return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array(
 
 function hl_version(){
 // version
 
 function hl_version(){
 // version
-return '1.2.4.1';
+return '1.2.5';
 }
 }
index 3eb07a57323f949f86a84add06b10331ea1ec060..13a75d5f7c6e6033e33c911f5638d2955df3d392 100644 (file)
@@ -111,8 +111,8 @@ span.totop a, span.totop a:visited {color: #6699cc;}
 
 <div id="body">
 <br />
 
 <div id="body">
 <br />
-<div class="comment">htmLawed_README.txt, 12 September 2017<br />
-htmLawed 1.2.4.1, 12 September 2017<br />
+<div class="comment">htmLawed_README.txt, 24 September 2019<br />
+htmLawed 1.2.5, 24 September 2019<br />
 Copyright Santosh Patnaik<br />
 Dual licensed with LGPL 3 and GPL 2+<br />
 A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>&#160;</div>
 Copyright Santosh Patnaik<br />
 Dual licensed with LGPL 3 and GPL 2+<br />
 A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>&#160;</div>
@@ -1127,7 +1127,7 @@ A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phpl
 &#160; * &#160;big - <span class="term">span style="font-size&#58; larger;"</span><br />
 &#160; * &#160;center - <span class="term">div style="text-align&#58; center;"</span><br />
 &#160; * &#160;dir - <span class="term">ul</span><br />
 &#160; * &#160;big - <span class="term">span style="font-size&#58; larger;"</span><br />
 &#160; * &#160;center - <span class="term">div style="text-align&#58; center;"</span><br />
 &#160; * &#160;dir - <span class="term">ul</span><br />
-&#160; * &#160;font (face, size, color) - &#160; &#160;<span class="term">span style="font-family&#58; ; font-size&#58; ; color&#58; ;"</span>&#160;(size transformation <a href="http://style.cleverchimp.com/font_size_intervals/altintervals.html">reference</a>)<br />
+&#160; * &#160;font (face, size, color) - &#160; &#160;<span class="term">span style="font-family&#58; ; font-size&#58; ; color&#58; ;"</span>&#160;(size transformation <a href="http://web.archive.org/web/20180201141931/http://style.cleverchimp.com/font_size_intervals/altintervals.html">reference</a>)<br />
 &#160; * &#160;isindex - based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>)<br />
 &#160; * &#160;s - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
 &#160; * &#160;strike - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
 &#160; * &#160;isindex - based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>)<br />
 &#160; * &#160;s - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
 &#160; * &#160;strike - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
@@ -1153,7 +1153,7 @@ A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phpl
 <code class="code">&#160; &#160; &lt;div style="text-align&#58; center;"&gt;</code>
 <br />
 
 <code class="code">&#160; &#160; &lt;div style="text-align&#58; center;"&gt;</code>
 <br />
 
-<code class="code">&#160; &#160; &#160;The PHP &lt;span style="text-decoration&#58; line-through;"&gt;software&lt;/span&gt; script used for this &lt;span style="text-decoration&#58; line-through;"&gt;web-page&lt;/span&gt; web-page is &lt;span style="font-weight&#58; bold; font-family&#58; arial; color&#58; red; font-size&#58; 200%;"&gt;htmLawedTest.php&lt;/span&gt;, from &lt;span style="color&#58;green; text-decoration&#58; underline;"&gt;PHP Labware&lt;/span&gt;.</code>
+<code class="code">&#160; &#160; &#160;The PHP &lt;span style="text-decoration&#58; line-through;"&gt;software&lt;/span&gt; script used for this &lt;span style="text-decoration&#58; line-through;"&gt;web-page&lt;/span&gt; web-page is &lt;span style="font-weight&#58; bold; font-size&#58; 200%; color&#58; red; font-family&#58; arial;"&gt;htmLawedTest.php&lt;/span&gt;, from &lt;u style="color&#58;green"&gt;PHP Labware&lt;/u&gt;.</code>
 <br />
 
 <code class="code">&#160; &#160; &lt;/div&gt;</code>
 <br />
 
 <code class="code">&#160; &#160; &lt;/div&gt;</code>
@@ -1670,7 +1670,7 @@ A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phpl
 <code class="code">&#160; &#160; &#160; if($element == &#39;object&#39;){</code>
 <br />
 
 <code class="code">&#160; &#160; &#160; if($element == &#39;object&#39;){</code>
 <br />
 
-<code class="code">&#160; &#160; &#160; &#160; $new_element = &#39;&lt;param id=&#39;my_&#39;. $id; allowscriptaccess="never" /&gt;&#39;;</code>
+<code class="code">&#160; &#160; &#160; &#160; $new_element = &#39;&lt;param id="my_&#39;. $id. &#39;"; allowscriptaccess="never" /&gt;&#39;;</code>
 <br />
 
 <code class="code">&#160; &#160; &#160; &#160; ++$id;</code>
 <br />
 
 <code class="code">&#160; &#160; &#160; &#160; ++$id;</code>
@@ -1827,6 +1827,10 @@ A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phpl
 <br />
 &#160; <em>Version number - Release date. Notes</em><br />
 <br />
 <br />
 &#160; <em>Version number - Release date. Notes</em><br />
 <br />
+&#160; 1.2.5 - 24 September 2019. Fixes two bugs in <span class="term">font</span>&#160;tag transformation<br />
+<br />
+&#160; 1.2.4.2 - 16 May 2019. Corrects a PHP notice if a semi-colon is present in <span class="term">$config["schemes"]</span><br />
+<br />
 &#160; 1.2.4.1 - 12 September 2017. Corrects a function re-declaration bug introduced in version 1.2.4<br />
 <br />
 &#160; 1.2.4 - 31 August 2017. Removes use of PHP <span class="term">create_function</span>&#160;function and <span class="term">$php_errormsg</span>&#160;reserved variable (deprecated in PHP 7.2)<br />
 &#160; 1.2.4.1 - 12 September 2017. Corrects a function re-declaration bug introduced in version 1.2.4<br />
 <br />
 &#160; 1.2.4 - 31 August 2017. Removes use of PHP <span class="term">create_function</span>&#160;function and <span class="term">$php_errormsg</span>&#160;reserved variable (deprecated in PHP 7.2)<br />
@@ -2278,7 +2282,7 @@ A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phpl
 </div>
 </div>
 <br />
 </div>
 </div>
 <br />
-<hr /><br /><br /><span class="subtle"><small>HTM version of <em><a href="htmLawed_README.txt">htmLawed_README.txt</a></em> generated on 12 Sep, 2017 using <a href="http://www.bioinformatics.org/phplabware/internal_utilities">rTxt2htm</a> from PHP Labware</small></span>
+<hr /><br /><br /><span class="subtle"><small>HTM version of <em><a href="htmLawed_README.txt">htmLawed_README.txt</a></em> generated on 25 Sep, 2019 using <a href="http://www.bioinformatics.org/phplabware/internal_utilities">rTxt2htm</a> from PHP Labware</small></span>
 </div><!-- ended div body -->
 </div><!-- ended div top -->
 </body>
 </div><!-- ended div body -->
 </div><!-- ended div top -->
 </body>
index e898bbfd621ab975c62c49a53d6d72e77c73824c..bf0a26da0c4f11f8cd4310fb065f42762cfbdc44 100644 (file)
@@ -2,10 +2,9 @@ name: htmLawed HTML filter/purifier
 description: Use htmLawed to restrict and correct HTML for compliance with admin. policy and standards and for security
 type: module
 package: filter
 description: Use htmLawed to restrict and correct HTML for compliance with admin. policy and standards and for security
 type: module
 package: filter
-core: 8.x
+core: 8.x
 
 
-# Information added by Drupal.org packaging script on 2018-07-05
-version: '8.x-3.5'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-04-11
+version: '8.x-3.7'
 project: 'htmlawed'
 project: 'htmlawed'
-datestamp: 1530751729
+datestamp: 1586586868
index 3415474ceee6e7b9eef6f21bb1ef1eeb0a71966d..90015a8864be5223636350950b28ebae2a95ae5d 100644 (file)
-htmLawed Drupal 8 module
+CONTENTS OF THIS FILE
+---------------------
 
 
-By Santosh Patnaik
-Since November 2015
-Dual licensed with LGPL 3+ and GPL 2+
+ * Introduction
+ * Requirements
+ * Installation
+ * Configuration
+ * Maintainers
 
 
-ABOUT
-====================================
 
 
-The htmLawed module uses the htmLawed PHP library (www.bioinformatics.org/phplabware/internal_utilities/htmLawed) to restrict and purify HTML for compliance with admin. policy and standards and for security.
+INTRODUCTION
+------------
 
 
-The module's directory includes the htmLawed PHP library and htmLawed documentation in its 'htmLawed' sub-directory. The content of the sub-directory can be replaced with that for the latest htmLawed version from www.bioinformatics.org/phplabware/internal_utilities/htmLawed.
+The htmLawed module uses the htmLawed PHP library to restrict and purify HTML
+for compliance with site administrator policy and standards and for security.
+Use of the htmLawed library allows for highly customizable control of HTML
+markup.
 
 
-If the htmLawed PHP library has been installed through the Libraries Drupal module, then the htmLawed module will use that library, and not the library in the htmLawed module's 'htmLawed' sub-directory.
+ * For a full description of the module, visit the project page:
+   https://www.drupal.org/project/htmlawed
+   or https://www.drupal.org/node/255886
 
 
-The Drupal website may have a handbook and other pages detailing htmLawed module usage (http://drupal.org/node/255886 and https://www.drupal.org/search/site/htmlawed?f[0]=ss_meta_type%3Adocumentation).
-
-INSTALLATION
-====================================
-
-Place the htmLawed module directory ('htmlawed') in an appropriate location within the Drupal installation directory, such as within its 'modules' directory.
-
-Then administer your Drupal website to enable the module.
-
-Note that if the htmLawed PHP library has been installed through the Libraries Drupal module, then the htmLawed module will use that library, and not the library in the htmLawed module's 'htmLawed' sub-directory.
+ * To submit bug reports and feature suggestions, or to track changes:
+   https://www.drupal.org/project/issues/htmlawed
 
 
 
 
-USAGE
-====================================
+REQUIREMENTS
+------------
 
 
-To enable and/or configure the htmLawed filter, such as for a text format, visit the text formats section of your Drupal website and configure the text format that will use or uses the filter.
+This module requires no modules outside of Drupal core.
 
 
-More than one text format can use the filter, each configured with its own settings for the filter. The htmLawed filter is configured by providing values in the form for its settings. The 'Config.' form-field is filled with comma-separated, quoted, key-value pairs like:
 
 
-'safe'=>1, 'element'=>'a, em, strong'
+INSTALLATION
+------------
 
 
-(These are interpreted as PHP array elements).
+ * Install the htmLawed module as you would normally install a contributed
+   Drupal module. Visit https://www.drupal.org/node/1897420 for further
+   information.
 
 
-The 'Spec.' form-field is an optional string of unquoted text. See the htmLawed documentation for more on how 'Config.' and 'Spec.' can be set, for instance, to permit all HTML, or restrict links to only certain domains. The default htmLawed filter settings allow the use of the a, em, strong, cite, code, ol, ul, li, dl, dt, dd, br and p HTML tags, and deny the id and style HTML attributes, and any unsafe markup (such as the the scriptable onclick attribute).
+Note: If the htmLawed PHP library has been installed through the Libraries
+Drupal module, then the htmLawed module will use that library, and not the
+library in the htmLawed module's 'htmLawed' sub-directory.
 
 
-Content in the 'Short tip' and 'Long tip' form-fields are used to inform users about the filter, such as about the tags that are allowed.
 
 
-To allow HTML comments such as the one used for the Drupal teaser-break indicator (<!--break-->), add "'comment' => 2" to the 'Config.' value of the htmLawed settings. To allow PHP codes (flanked by '<?php' and '?>') add "'save_php' => 1" to the 'Config.' value of the htmLawed settings.
+CONFIGURATION
+-------------
 
 
-Depending on the types of other filters in use, you may need to re-arrange the processing order of filters. The htmLawed filter would usually be the last filter to be run. If a filter generates HTML markup and is run before htmLawed, then htmLawed should be configured appropriately to permit such markup.
+To enable and/or configure the htmLawed filter, such as for a text format, visit
+the text formats section of your Drupal website and configure the text format
+that will use or uses the filter.
 
 
-Any in-built Drupal actions/filters to restrict HTML, correct broken HTML, or balance or properly nest HTML tags can be disabled since htmLawed performs these tasks. The htmLawed filter can also be used to restrict HTML attributes, limit URL protocols, etc. Note that htmLawed does not convert URLs into links nor does it convert line breaks into HTML.
+More than one text format can use the filter, each configured with its own
+settings for the filter. The htmLawed filter is configured by providing values
+in the form for its settings. The 'Config.' form-field is filled with
+comma-separated, quoted, key-value pairs like:
 
 
-It is important to understand the security implications of the htmLawed settings in use and the limitations of htmLawed. To keep the htmLawed library included with the module updated, replace the 'htmLawed.php' and 'htmLawed_README.htm' files inside the 'htmLawed' sub-directory of the htmLawed module directory ('htmlawed') with newer versions downloaded from the htmLawed website (www.bioinformatics.org/phplabware/internal_utilities/htmLawed). If the htmLawed library is being used through the Libraries Drupal module, use that module to update the library.
+```
+'safe'=>1, 'element'=>'a, em, strong'
+```
 
 
-HELP
-====================================
+(These are interpreted as PHP array elements).
 
 
-Visit the module's website at https://www.drupal.org/project/htmlawed.
\ No newline at end of file
+The 'Spec.' form-field is an optional string of unquoted text. Visit the
+htmLawed documentation for more on how 'Config.' and 'Spec.' can be set, for 
+instance, to permit all HTML, or restrict links to only certain domains. The
+default htmLawed filter settings allow the use of the a, em, strong, cite,
+code, ol, ul, li, dl, dt, dd, br and p HTML tags, and deny the id and style
+HTML attributes, and any unsafe markup (such as the scriptable onclick
+attribute).
+
+Content in the 'Short tip' and 'Long tip' form-fields are used to inform users
+about the filter, such as about the tags that are allowed.
+
+To allow HTML comments such as the one used for the Drupal teaser-break
+indicator (<!--break-->), add "'comment' => 2" to the 'Config.' value of the
+htmLawed settings. To allow PHP codes (flanked by '<?php' and '?>') add
+"'save_php' => 1" to the 'Config.' value of the htmLawed settings.
+
+Depending on the types of other filters in use, you may need to re-arrange the
+processing order of filters. The htmLawed filter would usually be the last
+filter to be run. If a filter generates HTML markup and is run before htmLawed,
+then htmLawed should be configured appropriately to permit such markup.
+
+Any in-built Drupal actions/filters to restrict HTML, correct broken HTML, or
+balance or properly nest HTML tags can be disabled since htmLawed performs
+these tasks. The htmLawed filter can also be used to restrict HTML attributes,
+limit URL protocols, etc. Note that htmLawed does not convert URLs into links
+nor does it convert line breaks into HTML.
+
+It is important to understand the security implications of the htmLawed settings
+in use and the limitations of htmLawed. To keep the htmLawed library included
+with the module updated, replace the 'htmLawed.php' and 'htmLawed_README.htm'
+files inside the 'htmLawed' sub-directory of the htmLawed module directory
+('htmlawed') with newer versions downloaded from the htmLawed website
+(www.bioinformatics.org/phplabware/internal_utilities/htmLawed). If the htmLawed
+library is being used through the Libraries Drupal module, use that module to
+update the library.
+
+
+MAINTAINERS
+-----------
+
+ * alpha2zee - https://www.drupal.org/u/alpha2zee
index 6585918ae62e1e52927499e98342d0d4a3cf5b7c..3a35b72e4348ada67188ac733b5a109d96f400b7 100644 (file)
@@ -12,6 +12,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\filter\FilterProcessResult;
 use Drupal\filter\Plugin\FilterBase;
 use Drupal\Core\Url;
 use Drupal\filter\FilterProcessResult;
 use Drupal\filter\Plugin\FilterBase;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Provides for use of htmLawed
 
 /**
  * Provides for use of htmLawed
@@ -36,11 +37,13 @@ use Drupal\filter\Plugin\FilterBase;
 
 class Filterhtmlawed extends FilterBase {
 
 
 class Filterhtmlawed extends FilterBase {
 
+  use StringTranslationTrait;
+
   /**
    * {@inheritdoc}
    */
   public function process($text, $langcode) {
   /**
    * {@inheritdoc}
    */
   public function process($text, $langcode) {
-  
+
     // Use htmLawed filter settings for the $config and $spec arguments to htmLawed();
     // use default values if needed.
     $htmLawed_settings = $this->settings;
     // Use htmLawed filter settings for the $config and $spec arguments to htmLawed();
     // use default values if needed.
     $htmLawed_settings = $this->settings;
@@ -51,13 +54,13 @@ class Filterhtmlawed extends FilterBase {
     if (!is_array($config)) {
       $config = array('safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd, br, p', 'deny_attribute'=>'id, style');
     }
     if (!is_array($config)) {
       $config = array('safe'=>1, 'elements'=>'a, em, strong, cite, code, ol, ul, li, dl, dt, dd, br, p', 'deny_attribute'=>'id, style');
     }
-    
+
     // If PHP code blocks are to be preserved, hide the special characters
     // like '<' of '<?php'.The 'save_php' parameter is NOT an htmLawed parameter per se.
     if (!empty($config['save_php'])) {
       $text = preg_replace_callback('`<\?php(.+?)\?>|<\?php(.*?)$`sm', function($m){return "\x83?php". str_replace(array('<', '>', '&'), array('&lt;', '&gt;', '&amp;'), $m[1]). (substr($m[0], -2) == '?>' ? "?\84" : '');}, $text);
     }
     // If PHP code blocks are to be preserved, hide the special characters
     // like '<' of '<?php'.The 'save_php' parameter is NOT an htmLawed parameter per se.
     if (!empty($config['save_php'])) {
       $text = preg_replace_callback('`<\?php(.+?)\?>|<\?php(.*?)$`sm', function($m){return "\x83?php". str_replace(array('<', '>', '&'), array('&lt;', '&gt;', '&amp;'), $m[1]). (substr($m[0], -2) == '?>' ? "?\84" : '');}, $text);
     }
-    
+
     // If Libraries module (API 3.x) is enabled, use htmLawed library through it;
     // else use the htmLawed library provided with the htmLawed module.
     $module_path = drupal_get_path('module', 'htmlawed');
     // If Libraries module (API 3.x) is enabled, use htmLawed library through it;
     // else use the htmLawed library provided with the htmLawed module.
     $module_path = drupal_get_path('module', 'htmlawed');
@@ -71,16 +74,16 @@ class Filterhtmlawed extends FilterBase {
 
     // htmLawed filtering.
     $text = htmLawed($text, $config, $htmLawed_settings['spec']);
 
     // htmLawed filtering.
     $text = htmLawed($text, $config, $htmLawed_settings['spec']);
-    
+
     // In case Drupal's teaser-break is in use;
     // since htmLawed corrects HTML comments to use the right format.
     $text = str_replace('<!--break -->', '<!--break-->', $text);
     // In case Drupal's teaser-break is in use;
     // since htmLawed corrects HTML comments to use the right format.
     $text = str_replace('<!--break -->', '<!--break-->', $text);
-    
+
     // Handle any PHP code preservation.
     if (!empty($config['save_php'])) {
       $text = preg_replace_callback('`\x83\?php(.+?)\?\x84|\x83\?php(.*?)$`sm', function($m){return "<?php". str_replace(array('&amp;', '&lt;', '&gt;'), array('&', '<', '>'), $m[1]). (substr($m[0], -2) == "?\x84" ? "?>" : '');}, $text);
     }
     // Handle any PHP code preservation.
     if (!empty($config['save_php'])) {
       $text = preg_replace_callback('`\x83\?php(.+?)\?\x84|\x83\?php(.*?)$`sm', function($m){return "<?php". str_replace(array('&amp;', '&lt;', '&gt;'), array('&', '<', '>'), $m[1]). (substr($m[0], -2) == "?\x84" ? "?>" : '');}, $text);
     }
-    
+
     // Return value.
     $result = new FilterProcessResult($text);
     return $result;
     // Return value.
     $result = new FilterProcessResult($text);
     return $result;
@@ -92,7 +95,7 @@ class Filterhtmlawed extends FilterBase {
   public function settingsForm(array $form, FormStateInterface $form_state) {
     $htmLawed_settings = $this->settings;
     $form['config'] = array(
   public function settingsForm(array $form, FormStateInterface $form_state) {
     $htmLawed_settings = $this->settings;
     $form['config'] = array(
-      '#prefix' => t('<a href=":url">Help</a>', array(':url' => Url::fromUri('base:admin/help/htmlawed')->toString())),
+      '#prefix' => $this->t('<a href=":url">Help</a>', array(':url' => Url::fromUri('base:admin/help/htmlawed')->toString())),
       '#type' => 'textarea',
       '#rows' => '2',
       '#title' => $this->t('Config.'),
       '#type' => 'textarea',
       '#rows' => '2',
       '#title' => $this->t('Config.'),
@@ -125,11 +128,11 @@ class Filterhtmlawed extends FilterBase {
 
   /**
    * {@inheritdoc}
 
   /**
    * {@inheritdoc}
-   */  
+   */
   public function tips($long = FALSE) {
     $htmLawed_settings = $this->settings;
     $help = !$long ? Html::escape($htmLawed_settings['help']) : Html::escape($htmLawed_settings['helplong']);
   public function tips($long = FALSE) {
     $htmLawed_settings = $this->settings;
     $help = !$long ? Html::escape($htmLawed_settings['help']) : Html::escape($htmLawed_settings['helplong']);
-    $help = !empty($help) ? $help : (!$long ? t('HTML markup is restricted/corrected with the htmLawed filter.') : t('HTML markup is restricted/corrected with the @htmLawed filter for compliance with admin. policy and standards and for security. More details about the restrictions in effect may be available elsewhere, such as in the text of the filter-tips of text formats that use htmLawed and on the forms for configuring text formats.', array('@htmLawed' => \Drupal::l('htmLawed', Url::fromUri('http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed')))) . (!\Drupal::currentUser()->hasPermission('administer filters') ? '' : t(' For information on configuring the htmLawed filter, visit the htmLawed module @help section.', array('@help' => \Drupal::l(t('help'), Url::fromUri('base:admin/help/htmlawed'))))));
+    $help = !empty($help) ? $help : (!$long ? $this->t('HTML markup is restricted/corrected with the htmLawed filter.') : $this->t('HTML markup is restricted/corrected with the @htmLawed filter for compliance with admin. policy and standards and for security. More details about the restrictions in effect may be available elsewhere, such as in the text of the filter-tips of text formats that use htmLawed and on the forms for configuring text formats.', array('@htmLawed' => \Drupal::l('htmLawed', Url::fromUri('http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed')))) . (!\Drupal::currentUser()->hasPermission('administer filters') ? '' : $this->t(' For information on configuring the htmLawed filter, visit the htmLawed module @help section.', array('@help' => \Drupal::l($this->t('help'), Url::fromUri('base:admin/help/htmlawed'))))));
     return $help;
   }
 }
     return $help;
   }
 }
diff --git a/web/modules/contrib/security_review/API.txt b/web/modules/contrib/security_review/API.txt
deleted file mode 100644 (file)
index 627e264..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-For the latest documentation and code examples go to:
-https://www.drupal.org/node/2508415
-
-# Security Review API
-
-  * Defining a security check
-    * Identifiers
-    * Action and messages
-    * Help page
-    * Evaluation page (optional)
-    * Check-specific settings (optional)
-      * Form generation
-      * Configuration schema
-  * Hooks
-  * Alterable variables
-  * Drush usage
-
-## Defining a security check
-
-  This part of the documentation lets the developer understand the behavior of
-  the module. If anything's unclear it is recommended to look at the examples.
-
-  To define a security check for Security Review, one has to create a class that
-  extends Drupal\security_review\Check.
-  The functions that must be overridden are the following:
-    * getNamespace()
-    * getTitle()
-    * run()
-    * help()
-    * getMessage()
-
-  ### Identifiers
-
-    There are 5 kinds of identifiers for a given check:
-      * namespace
-      * machine namespace
-      * title
-      * machine title
-      * id
-
-    The 'namespace' must be manually set for each check by overriding the
-    getNamespace() method. This is the human-readable namespace of the check
-    (usually the module's name).
-
-    The 'machine namespace' is the version of namespace that is used internally.
-    If getMachineNamespace() isn't overridden, then it is produced from the
-    human-readable namespace by removing any non-alphanumeric characters and
-    replacing spaces with underscores. When overriding getMachineNamespace()
-    this rule must be followed.
-
-    The 'title' must be manually set for each check by overriding the getTitle()
-    method. This is the human-readable title of the check.
-
-    The 'machine title' has the same relationship to 'title' as 'machine
-    namespace' has to 'namespace'. The machine title should be unique to the
-    namespace. This might only be achievable by overriding getMachineTitle().
-
-    The 'id' is only used internally and cannot be overridden. It's constructed
-    by taking the 'machine namespace' and 'machine title' and putting a hyphen
-    between them.
-
-  ### Action and messages
-
-    The part where the actual security check happens is the run() method. This
-    method must be overridden, and should always return an instance of
-    Drupal\security_review\CheckResult.
-
-    Instantiating a CheckResult:
-
-    CheckResult defines one constructor:
-    (Check $check, $result, array $findings, $visible = TRUE, $time = NULL)
-      * $check
-        The Check that is responsible for the result
-      * $result
-        An integer that defines the outcome of the check:
-          * CheckResult::SUCCESS  - for a successful check
-          * CheckResult::FAIL     - for a failed check
-          * CheckResult::WARN     - for a check that only raised a warning
-          * CheckResult::INFO     - general result for providing information
-      * $findings
-        An array of findings that can be evaluated. It can be empty.
-      * $visible
-        Check results can be hidden from the user by setting $visible to FALSE.
-      * $time
-        Timestamp indicating the time when the result was produced. If left null
-        it will be the current time.
-
-    NOTE:
-    It's easier to instantiate a result with Check's createResult() method. It
-    has the same parameters as the constructor for CheckResult, except the
-    $check is left out (set to $this).
-
-    Human-readable messages for each result integer:
-
-    Must be defined by overriding the getMessage() method. The implementation is
-    usually a switch-case. For more details take a look at Security Review's own
-    Check implementations.
-
-  ### Help page
-
-    Every Check can have its own help page by overriding the help() method. This
-    should return a render array.
-    See https://www.drupal.org/developing/api/8/render/arrays
-
-  ### Evaluation page (optional)
-
-    The evaluation page is for providing an evaluation of a CheckResult produced
-    by the Check. Overriding this is optional, the default implementation
-    returns an empty array. If one chooses to override evaluate(), the function
-    must return a render array.
-    See https://www.drupal.org/developing/api/8/render/arrays
-
-  ### Check-specific settings (optional)
-
-    If the Check requires storage for settings, it can be accessed via
-    $this->settings(). This method returns a
-    Drupal\security_review\CheckSettingsInterface. It has get() and set()
-    methods for accessing the stored configuration, and buildForm(),
-    submitForm(), validateForm() for form building. By default Check's
-    implementation contains a Drupal\security_review\CheckSettings, which stores
-    the values in the Configuration system, and does nothing in its form
-    building methods. Usually it's enough to extend this class if the Check
-    needs separate settings on the Security Review settings page.
-
-    When using check-specific settings it's recommended to define a
-    configuration schema to store the values in their correct types. The schema
-    to declare is called security_review.check_settings.[id of check] .
-
-## Hooks
-
-  ### hook_security_review_checks()
-
-    To let Security Review know of the checks defined in the module it has to
-    implement hook_security_review_checks(). This hook is fairly simple. It has
-    to return an array of check instances.
-
-    For example implementations see security_review.api.php and
-    security_review.module and the examples.
-
-  ### hook_security_review_log()
-
-    Provides logging functions for various events:
-    Check skipped / enabled
-    Check ran
-    Check gave a NULL result
-
-    For example implementations see security_review.api.php and
-    security_review.module.
-
-## Alterable variables
-
-  To understand what alterable variables are, take a look at
-  https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Extension!ModuleHandler.php/function/ModuleHandler%3A%3Aalter/8
-  To modify an alterable variable you have to implement hook_[TYPE]_alter.
-  An example:
-
-  <?php
-  // ...
-  /**
-   * Implements hook_security_review_unsafe_extensions_alter().
-   */
-  function my_module_security_review_unsafe_extensions_alter(array &$variable) {
-    // Add the .reg file extension to the list of unsafe extensions.
-    $variable[] = 'reg';
-  }
-  ?>
-
-  ### security_review_unsafe_tags
-
-    The list of HTML tags considered to be unsafe.
-    See https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet .
-
-    Default variable content is at Security::unsafeTags().
-
-  ### security_review_unsafe_extensions
-
-    The list of file extensions considered to be unsafe for upload. Untrusted
-    users should not be allowed to upload files of these extensions.
-
-    Default variable content is at Security::unsafeExtensions().
-
-  ### security_review_file_ignore
-
-    The list of relative and absolute paths to ignore when running the File
-    permissions check.
-
-    Default variable content is at FilePermissions::run().
-
-  ### security_review_temporary_files
-
-    The list of files to check for the Temporary files security check.
-
-    Default variable definition is at TemporaryFiles::run().
-
-## Drush usage
-
-  Run the checklist via Drush with the "drush security-review" command.
-  Consult the Drush help on the security-review command for more information.
diff --git a/web/modules/contrib/security_review/IGNOREME.txt b/web/modules/contrib/security_review/IGNOREME.txt
deleted file mode 100644 (file)
index 72e8e13..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-You should read the README.txt but can ignore this file. It is used as part of
-the test to see if files are writable on your site. If you see timestamps below
-this line those are security runs which were able to write to this file.
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-20160608114206 - Your web server should not be able to write to your modules directory. This is a security vulnerable. Consult the Security Review file permissions check help for mitigation steps.
diff --git a/web/modules/contrib/security_review/PATCHES.txt b/web/modules/contrib/security_review/PATCHES.txt
deleted file mode 100644 (file)
index 3294fe1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)
-Patches applied to this directory:
-
-Fix missing field review list
-Source: https://www.drupal.org/files/issues/security_review-dangerous-tags-list-2744805-2.patch
-
-
diff --git a/web/modules/contrib/security_review/README.txt b/web/modules/contrib/security_review/README.txt
deleted file mode 100644 (file)
index 03e7304..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-
--- ABOUT --
-
-Security Review automates checking many of the configuration errors that lead
-to an insecure Drupal site and looks for existing vulnerabilities and attack
-attempts.
-
-The primary goal of the module is to elevate your awareness of the importance of
-securing your Drupal site. The results of some checks may be incorrect depending
-on unique factors, this module does not make your site more secure. You should
-use the results of the checklist and its resources to manually secure your site.
-
-Refer to the support section below if you are interested in securing your Drupal
-site.
-
--- INSTALLATION --
-
-Place the security_review directory and its contents under /modules or a
-subdirectory of /modules in the Drupal root directory.
-
-Enable the module at Administer >> Modules and refer to the
-following sections for configuration and usage.
-
--- CONFIGURATION --
-
-Two permissions are provided and required to use the module. Navigate to
-Administer >> People >> Permissions to enable
-'access security review list' and 'run security checks' for trusted roles.
-
-NOTICE: This module provides information on the state of your site's security so
-it is imperative you grant these permissions to trusted roles and users only.
-For instance, if you have an admin role, be sure that all the users who have
-been granted this role are indeed users you trust if you grant them these
-permissions.
-
-After you have granted permissions to the module you should inform the system
-what roles are not trusted. Navigate to
-Administer >> Reports >> Security Review >> Settings to mark which roles are
-untrusted. Most checks only care if the resource is usable by
-untrusted roles.
-
-On this page you can also define the level of logging. The result
-of the last checklist is always stored but you can enable watchdog logging of
-each check if you like.
-
--- USAGE --
-
-Navigate to Administer >> Reports >> Security Review to run the checklist.
-
-If a check is enabled it will be run. You can enable or skip a check on this
-page only after it has been run. Clicking on the 'Help' link beside each check
-will provide details on why the check exists and what was found on the last run.
-
--- DRUSH USAGE --
-
-Running the Security Review checklist using Drush is a great way to build
-automated security audits of your site into your site development lifecycle and
-as part of continuous integration.
-
-With the module installed invoke 'drush secrev' from within your Drupal root.
-
-Call 'drush help secrev' to see available options.
-
-For running specific checks pass the '--check' option. Be sure to remove any
-whitespace characters separating check names.
-
-Consult implementations of hook_security_checks() for exact list of available
-check options. Standard Security Review checks are:
-
-file_perms, input_formats, field, error_reporting, private_files, query_errors,
-failed_logins, upload_extensions, admin_permissions, executable_php,
-trusted_hosts, temporary_files
-
-For custom checks you may prefix the check name with the module name and
-colon (:) character. For example:
-
-'drush secrev --check=my_module:my_check'
-
-Note, custom checks require that its module be enabled. Also, should you be
-skipping any check the 'store' option will not allow that check to be run.
-
--- SUPPORT --
-
-Please use the issue queue at http://drupal.org/project/security_review for all
-module support. You can read more about securely configuring your site at
-http://drupal.org/security/secure-configuration and http://drupalscout.com
-
--- CREDIT --
-
-Security Review module originally written by Benjamin Jeavons, drupal.org user
-coltrane. Ported to Drupal 8 by Viktor Bán.
diff --git a/web/modules/contrib/security_review/config/install/security_review.check.security_review-base_url_set.yml b/web/modules/contrib/security_review/config/install/security_review.check.security_review-base_url_set.yml
deleted file mode 100644 (file)
index 070f10a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-id: 'security_review-base_url_set'
-settings:
-  method: 'token'
diff --git a/web/modules/contrib/security_review/config/install/security_review.settings.yml b/web/modules/contrib/security_review/config/install/security_review.settings.yml
deleted file mode 100644 (file)
index fe575a5..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-configured: false
-untrusted_roles: []
-log: true
diff --git a/web/modules/contrib/security_review/config/schema/security_review.schema.yml b/web/modules/contrib/security_review/config/schema/security_review.schema.yml
deleted file mode 100644 (file)
index 3d30179..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-# The module's main settings.
-security_review.settings:
-  type: config_entity
-  mapping:
-    configured:
-      type: boolean
-      label: 'Has been configured'
-    untrusted_roles:
-      type: sequence
-      label: 'Untrusted roles'
-      sequence:
-        type: string
-        label: 'Role ID'
-    log:
-      type: boolean
-      label: 'Logging enabled'
-
-# Defines a security check's skip informations and settings.
-security_review.check.*:
-  type: config_entity
-  mapping:
-    id:
-      type: string
-      label: 'Check ID'
-    skipped:
-      type: boolean
-      label: 'Is skipped'
-    skipped_by:
-      type: integer
-      label: 'Skipped by'
-    skipped_on:
-      type: integer
-      label: 'Skipped on'
-    settings:
-      # Checks that need storage for settings are advised to define their settings schema.
-      # This way type-strict per-check settings storage can be created.
-      type: security_review.check_settings.[%parent.id]
-
-# Setting storage for Base URL check.
-security_review.check_settings.security_review-base_url_set:
-  type: mapping
-  mapping:
-    method:
-      type: string
-      label: 'Base URL identification method'
diff --git a/web/modules/contrib/security_review/css/security_review.run_and_review.css b/web/modules/contrib/security_review/css/security_review.run_and_review.css
deleted file mode 100644 (file)
index 56ed396..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-.security-review-run-and-review__table {
-  border: none;
-}
-
-.security-review-run-and-review__entry {
-  border-width: 1px 0 0 0;
-  border-style: solid;
-  border-color: #ccc;
-}
-
-.security-review-run-and-review__entry-icon {
-  width: 16px;
-}
-
-.security-review-run-and-review__entry:last-child {
-  border-bottom-width: 1px;
-}
-
-.security-review-run-and-review__entry.skipped {
-  color: #333333 !important;
-  background-color: #dddddd !important;
-}
-
-.security-review-run-and-review__entry.success {
-  color: #255b1e;
-  background-color: #e5ffe2;
-}
-
-.security-review-run-and-review__entry.fail {
-  color: #8c2e0b;
-  background-color: #fef5f1;
-}
-
-.security-review-run-and-review__entry.warning {
-  color: #734c00;
-  background-color: #fdf8ed;
-}
-
-.security-review-run-and-review__entry.info {
-  color: #000e6f;
-  background-color: #dfefff;
-}
diff --git a/web/modules/contrib/security_review/js/security_review.run_and_review.js b/web/modules/contrib/security_review/js/security_review.run_and_review.js
deleted file mode 100644 (file)
index f249e41..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * @file
- * Implementation of check toggling using AJAX.
- */
-
-(function ($) {
-  Drupal.behaviors.securityReview = {
-    attach: function (context) {
-      $(context).find('.security-review-toggle-link a').click(function () {
-        var link = $(this);
-        var url = link.attr('href');
-        var td = link.parent();
-        var tr = td.parent();
-        $.getJSON(url + '&js=1', function (data) {
-          if (data.skipped) {
-            tr.addClass('skipped');
-          }
-          else {
-            tr.removeClass('skipped');
-          }
-          link.text(data.toggle_text);
-          link.attr(data.toggle_href);
-        });
-        return false;
-      });
-    }
-  };
-})(jQuery);
diff --git a/web/modules/contrib/security_review/security_review.api.php b/web/modules/contrib/security_review/security_review.api.php
deleted file mode 100644 (file)
index 157689d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-/**
- * @file
- * Defines the API for Security Review.
- */
-
-/*
-use Drupal\mymodule\MyCheck;
-use Drupal\mymodule\MyOtherCheck;
- */
-use Drupal\security_review\Check;
-
-/**
- * Returns the array of security checks the module defines.
- *
- * The checks must extend \Drupal\security_review\Check.
- *
- * @return array
- *   An array of security checks.
- */
-function hook_security_review_checks() {
-  // Return instances of the defined Checks.
-  return [
-    /*
-    new MyCheck(),
-    new MyOtherCheck(),
-    */
-  ];
-}
-
-/**
- * Provides logging capabilities.
- *
- * @param \Drupal\security_review\Check $check
- *   The Check the event is related to.
- * @param string $message
- *   The message.
- * @param array $context
- *   The context of the message.
- * @param int $level
- *   Severity (RfcLogLevel).
- */
-function hook_security_review_log(Check $check, $message, array $context, $level) {
-  if ($check->getNamespace() == "My Module") {
-    // Do something with the information.
-  }
-}
diff --git a/web/modules/contrib/security_review/security_review.drush.inc b/web/modules/contrib/security_review/security_review.drush.inc
deleted file mode 100644 (file)
index 6931887..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-<?php
-
-/**
- * @file
- * Drush commands for Security Review module.
- */
-
-use Drupal\security_review\CheckResult;
-
-/**
- * Implements hook_drush_command().
- */
-function security_review_drush_command() {
-  $items = [];
-
-  $items['security-review'] = [
-    'aliases' => ['secrev'],
-    'callback' => 'security_review_drush',
-    'description' => "Run the Security Review checklist",
-    'options' => [
-      'store' => 'Write results to the database',
-      'log' => 'Log results of each check to watchdog, defaults to off',
-      'lastrun' => 'Do not run the checklist, just print last results',
-      'check' => 'Comma-separated list of specified checks to run. See README.txt for list of options',
-      'skip' => 'Comma-separated list of specified checks not to run. This takes precedence over --check.',
-      'short' => "Short result messages instead of full description (e.g. 'Text formats')",
-      'results' => 'Show the incorrect settings for failed checks',
-    ],
-    'examples' => [
-      'secrev' => 'Run the checklist and output the results',
-      'secrev --store' => 'Run the checklist, store, and output the results',
-      'secrev --lastrun' => 'Output the stored results from the last run of the checklist',
-    ],
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
-    'outputformat' => [
-      'default' => 'table',
-      'pipe-format' => 'csv',
-      'fields-default' => ['message', 'status'],
-      'field-labels' => [
-        'message' => 'Message',
-        'status' => 'Status',
-        'findings' => 'Findings',
-      ],
-      'output-data-type' => 'format-table',
-    ],
-  ];
-
-  return $items;
-}
-
-/**
- * Implements hook_drush_help().
- */
-function security_review_drush_help($section) {
-  switch ($section) {
-    case 'drush:security-review':
-      return dt("Run configuration security checks on your Drupal site.");
-  }
-}
-
-/**
- * Runs a checklist and displays results.
- */
-function security_review_drush() {
-  /** @var \Drupal\security_review\SecurityReview $security_review */
-  $security_review = Drupal::service('security_review');
-
-  /** @var \Drupal\security_review\Checklist $checklist */
-  $checklist = Drupal::service('security_review.checklist');
-
-  $store = drush_get_option('store');
-  $log = drush_get_option('log');
-  $last_run = drush_get_option('lastrun');
-  $run_checks = drush_get_option_list('check');
-  $skip_checks = drush_get_option_list('skip');
-  $short_titles = drush_get_option('short');
-  $show_findings = drush_get_option('results');
-
-  // Set temporary logging.
-  $log = in_array($log, [TRUE, 1, 'TRUE']);
-  $security_review->setLogging($log, TRUE);
-
-  if (!empty($short_titles)) {
-    $short_titles = TRUE;
-  }
-  else {
-    $short_titles = FALSE;
-  }
-
-  $results = [];
-  if (!$last_run) {
-    // Do a normal security review run.
-    /** @var \Drupal\security_review\Check[] $checks */
-    $checks = [];
-    /** @var \Drupal\security_review\Check[] $to_skip */
-    $to_skip = [];
-
-    // Fill the $checks array.
-    if (!empty($run_checks)) {
-      // Get explicitly specified checks.
-      foreach ($run_checks as $check) {
-        $checks[] = _security_review_drush_get_check($check);
-      }
-    }
-    else {
-      // Get the whole checklist.
-      $checks = $checklist->getChecks();
-    }
-
-    // Mark checks listed after --skip for removal.
-    if (!empty($skip_checks)) {
-      foreach ($skip_checks as $skip_check) {
-        $to_skip[] = _security_review_drush_get_check($skip_check);
-      }
-    }
-
-    // If storing, mark skipped checks for removal.
-    if ($store) {
-      foreach ($checks as $check) {
-        if ($check->isSkipped()) {
-          $to_skip[] = $check;
-        }
-      }
-    }
-
-    // Remove the skipped checks from $checks.
-    foreach ($to_skip as $skip_check) {
-      foreach ($checks as $key => $check) {
-        if ($check->id() == $skip_check->id()) {
-          unset($checks[$key]);
-        }
-      }
-    }
-
-    // If $checks is empty at this point, return with an error.
-    if (empty($checks)) {
-      return drush_set_error('EMPTY_CHECKLIST', dt("No checks to run. Run 'drush help secrev' for option use or consult the drush section of API.txt for further help."));
-    }
-
-    // Run the checks.
-    $results = $checklist->runChecks($checks, TRUE);
-
-    // Store the results.
-    if ($store) {
-      $checklist->storeResults($results);
-    }
-  }
-  else {
-    // Show the latest stored results.
-    foreach ($checklist->getChecks() as $check) {
-      $last_result = $check->lastResult($show_findings);
-      if ($last_result instanceof CheckResult) {
-        $results[] = $last_result;
-      }
-    }
-  }
-
-  return _security_review_drush_format_results($results, $short_titles, $show_findings);
-}
-
-/**
- * Helper function for parsing input check name strings.
- *
- * @param string $check_name
- *   The check to get.
- *
- * @return \Drupal\security_review\Check|null
- *   The found Check.
- */
-function _security_review_drush_get_check($check_name) {
-  /** @var \Drupal\security_review\Checklist $checklist */
-  $checklist = Drupal::service('security_review.checklist');
-
-  // Default namespace is Security Review.
-  $namespace = 'security_review';
-  $title = $check_name;
-
-  // Set namespace and title if explicitly defined.
-  if (strpos($check_name, ':') !== FALSE) {
-    list($namespace, $title) = explode(':', $check_name);
-  }
-
-  // Return the found check if any.
-  return $checklist->getCheck($namespace, $title);
-}
-
-/**
- * Helper function to compile Security Review results.
- *
- * @param \Drupal\security_review\CheckResult[] $results
- *   An array of CheckResults.
- * @param bool $short_titles
- *   Whether to use short message (check title) or full check success or failure
- *   message.
- * @param bool $show_findings
- *   Whether to print failed check results.
- *
- * @return array
- *   The results of the security review checks.
- */
-function _security_review_drush_format_results(array $results, $short_titles = FALSE, $show_findings = FALSE) {
-  $output = [];
-
-  foreach ($results as $result) {
-    if ($result instanceof CheckResult) {
-      if (!$result->isVisible()) {
-        // Continue with the next check.
-        continue;
-      }
-
-      $check = $result->check();
-      $message = $short_titles ? $check->getTitle() : $result->resultMessage();
-      $status = 'notice';
-
-      // Set log level according to check result.
-      switch ($result->result()) {
-        case CheckResult::SUCCESS:
-          $status = 'success';
-          break;
-
-        case CheckResult::FAIL:
-          $status = 'failed';
-          break;
-
-        case CheckResult::WARN:
-          $status = 'warning';
-          break;
-
-        case CheckResult::INFO:
-          $status = 'info';
-          break;
-      }
-
-      // Attach findings.
-      if ($show_findings) {
-        $findings = trim($result->check()->evaluatePlain($result));
-        if ($findings != '') {
-          $message .= "\n" . $findings;
-        }
-      }
-
-      $output[$check->id()] = [
-        'message' => (string) $message,
-        'status' => $status,
-        'findings' => $result->findings(),
-      ];
-    }
-  }
-
-  return $output;
-}
diff --git a/web/modules/contrib/security_review/security_review.info.yml b/web/modules/contrib/security_review/security_review.info.yml
deleted file mode 100644 (file)
index 5c810f8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-name: Security Review
-type: module
-description: 'Site security and configuration review module.'
-package: Security
-core: 8.x
-configure: security_review.settings
diff --git a/web/modules/contrib/security_review/security_review.install b/web/modules/contrib/security_review/security_review.install
deleted file mode 100644 (file)
index 9991149..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-/**
- * @file
- * Install, update and uninstall functions for the security_review module.
- */
-
-use Drupal\Core\Url;
-use Drupal\security_review\CheckResult;
-
-/**
- * Implements hook_install().
- */
-function security_review_install() {
-  // Remind the user to set the permissions.
-  drupal_set_message(
-    t(
-      'Security Review module enabled. You should first set the module access permissions at <a href=":url">admin/people/permissions</a>. Be sure to grant permissions to trusted users only as this module can show sensitive site information.',
-      [':url' => Url::fromRoute('user.admin_permissions')->toString()]
-    )
-  );
-}
-
-/**
- * Implements hook_requirements().
- */
-function security_review_requirements($phase) {
-  $requirements = [];
-
-  // Provides a Status Report entry.
-  if ($phase == 'runtime') {
-    /** @var \Drupal\security_review\Checklist $checklist */
-    $checklist = Drupal::service('security_review.checklist');
-
-    $failed_checks = FALSE;
-    $no_results = TRUE;
-
-    // Looks for failed checks.
-    foreach ($checklist->getEnabledChecks() as $check) {
-      $result = $check->lastResult();
-      if ($result instanceof CheckResult) {
-        $no_results = FALSE;
-        if ($result->result() === CheckResult::FAIL) {
-          $failed_checks = TRUE;
-          break;
-        }
-      }
-    }
-
-    $module_url = Url::fromRoute('security_review')->toString();
-    if ($no_results) {
-      $severity = REQUIREMENT_WARNING;
-      $value = t(
-        'The Security Review checklist has not been run. <a href=":url">Run the checklist</a>',
-        [':url' => $module_url]
-      );
-    }
-    elseif ($failed_checks) {
-      $severity = REQUIREMENT_WARNING;
-      $value = t(
-        'There are failed Security Review checks. <a href=":url">Review the checklist</a>',
-        [':url' => $module_url]
-      );
-    }
-    else {
-      $severity = REQUIREMENT_OK;
-      $value = t(
-        'Passing all non-ignored Security Review checks. <a href=":url">Review the checklist</a>',
-        [':url' => $module_url]
-      );
-    }
-    $requirements['security_review'] = [
-      'title' => t('Security Review'),
-      'severity' => $severity,
-      'value' => $value,
-    ];
-  }
-
-  return $requirements;
-}
diff --git a/web/modules/contrib/security_review/security_review.libraries.yml b/web/modules/contrib/security_review/security_review.libraries.yml
deleted file mode 100644 (file)
index 0eccdf9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-run_and_review:
-  version: VERSION
-  css:
-    theme:
-      css/security_review.run_and_review.css: {}
-  js:
-    js/security_review.run_and_review.js: {}
-  dependencies:
-    - core/jquery
-    - core/drupal
diff --git a/web/modules/contrib/security_review/security_review.links.menu.yml b/web/modules/contrib/security_review/security_review.links.menu.yml
deleted file mode 100644 (file)
index 89ec97a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-security_review:
-  route_name: security_review
-  title: 'Security review'
-  description: 'Perform a review of the security of your site.'
-  parent: system.admin_reports
-
-security_review.settings:
-  route_name: security_review.settings
-  title: 'Security Review'
-  description: 'Choose which roles are untrusted, set logging, skip or enable security checks and modify check-specific settings.'
-  parent: system.admin_config_system
diff --git a/web/modules/contrib/security_review/security_review.links.task.yml b/web/modules/contrib/security_review/security_review.links.task.yml
deleted file mode 100644 (file)
index 64278e8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-security_review:
-  route_name: security_review
-  title: 'Run & review'
-  base_route: security_review
-
-security_review.help:
-  route_name: security_review.help
-  title: 'Help'
-  weight: 10
-  base_route: security_review
-
-security_review.settings:
-  route_name: security_review.settings
-  title: 'Settings'
-  weight: 15
-  base_route: security_review
diff --git a/web/modules/contrib/security_review/security_review.module b/web/modules/contrib/security_review/security_review.module
deleted file mode 100644 (file)
index 508f625..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-<?php
-
-/**
- * @file
- * Site security review and reporting Drupal module.
- */
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\Url;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-use Drupal\security_review\Checks\AdminPermissions;
-use Drupal\security_review\Checks\ErrorReporting;
-use Drupal\security_review\Checks\ExecutablePhp;
-use Drupal\security_review\Checks\FailedLogins;
-use Drupal\security_review\Checks\Field;
-use Drupal\security_review\Checks\FilePermissions;
-use Drupal\security_review\Checks\InputFormats;
-use Drupal\security_review\Checks\PrivateFiles;
-use Drupal\security_review\Checks\QueryErrors;
-use Drupal\security_review\Checks\TemporaryFiles;
-use Drupal\security_review\Checks\TrustedHosts;
-use Drupal\security_review\Checks\UploadExtensions;
-use Drupal\security_review\Checks\ViewsAccess;
-
-/**
- * Implements hook_security_review_checks().
- */
-function security_review_security_review_checks() {
-  return [
-    new AdminPermissions(),
-    new ErrorReporting(),
-    new ExecutablePhp(),
-    new FailedLogins(),
-    new Field(),
-    new FilePermissions(),
-    new InputFormats(),
-    new PrivateFiles(),
-    new QueryErrors(),
-    new TemporaryFiles(),
-    new TrustedHosts(),
-    new UploadExtensions(),
-    new ViewsAccess(),
-  ];
-}
-
-/**
- * Implements hook_security_review_log().
- */
-function security_review_security_review_log(Check $check, $message, array $context, $level) {
-  Drupal::logger('security_review')->log($level, $message, $context);
-}
-
-/**
- * Implements hook_modules_uninstalled().
- */
-function security_review_modules_uninstalled($modules) {
-  /** @var \Drupal\security_review\SecurityReview $security_review */
-  $security_review = Drupal::service('security_review');
-
-  // Clean orphaned checks.
-  $security_review->cleanStorage();
-}
-
-/**
- * Implements hook_modules_installed().
- */
-function security_review_modules_installed($modules) {
-  // Post-install hook.
-  if (in_array('security_review', $modules)) {
-
-    /** @var \Drupal\security_review\SecurityReview $security_review */
-    $security_review = Drupal::service('security_review');
-
-    // Clean orphaned checks.
-    $security_review->cleanStorage();
-
-    // Store the web server's user.
-    $security_review->setServerData();
-  }
-}
-
-/**
- * Implements hook_theme().
- */
-function security_review_theme($existing, $type, $theme, $path) {
-  return [
-    'check_evaluation' => [
-      'template' => 'check_evaluation',
-      'variables' => [
-        'paragraphs' => [],
-        'items' => [],
-      ],
-    ],
-    'check_help' => [
-      'template' => 'check_help',
-      'variables' => [
-        'title' => [],
-        'paragraphs' => [],
-      ],
-    ],
-    'general_help' => [
-      'template' => 'general_help',
-      'variables' => [
-        'paragraphs' => [],
-        'checks' => [],
-      ],
-    ],
-    'run_and_review' => [
-      'template' => 'run_and_review',
-      'variables' => [
-        'date' => [],
-        'checks' => [],
-      ],
-    ],
-  ];
-}
-
-/**
- * Preprocesses variables for template 'run_and_review'.
- */
-function template_preprocess_run_and_review(&$variables) {
-  // Get icon list.
-  $icons_root = '/core/misc/icons/';
-  $variables['icons'] = [
-    'success' => $icons_root . '73b355/check.svg',
-    'warning' => $icons_root . 'e29700/warning.svg',
-    'fail' => $icons_root . 'e32700/error.svg',
-  ];
-
-  // Generate full URLs.
-  foreach ($variables['icons'] as $icon => $path) {
-    $variables['icons'][$icon] = Url::fromUserInput($path)->setAbsolute()
-      ->toString();
-  }
-
-  // Format date.
-  $variables['date'] = \Drupal::service('date.formatter')->format($variables['date']);
-
-  // Convert check result integers to strings.
-  foreach ($variables['checks'] as &$check) {
-    if (isset($check['result'])) {
-      switch ($check['result']) {
-        case CheckResult::SUCCESS:
-          $check['result'] = 'success';
-          break;
-
-        case CheckResult::FAIL:
-          $check['result'] = 'fail';
-          break;
-
-        case CheckResult::WARN:
-          $check['result'] = 'warning';
-          break;
-
-        case CheckResult::INFO:
-          $check['result'] = 'info';
-          break;
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_cron().
- */
-function security_review_cron() {
-  // Store the web server's user.
-  Drupal::service('security_review')->setServerData();
-}
-
-/**
- * Batch operation: runs a single check.
- *
- * @param \Drupal\security_review\Check $check
- *   The check to run.
- * @param array $context
- *   The Batch context.
- */
-function _security_review_batch_run_op(Check $check, array &$context) {
-  // Inform the user about the progress.
-  $context['message'] = $check->getTitle();
-
-  // Run the check.
-  $results = Drupal::service('security_review.checklist')
-    ->runChecks([$check]);
-
-  // Store the results.
-  $context['results'] = array_merge($context['results'], $results);
-}
-
-/**
- * Callback for finishing the batch job of running the checklist.
- *
- * @param bool $success
- *   Whether the batch job was successful.
- * @param \Drupal\security_review\CheckResult[] $results
- *   The results of the batch job.
- * @param array $operations
- *   The array of batch operations.
- */
-function _security_review_batch_run_finished($success, array $results, array $operations) {
-  /** @var \Drupal\security_review\SecurityReview $security_review */
-  $security_review = Drupal::service('security_review');
-
-  /** @var \Drupal\security_review\Checklist $checklist */
-  $checklist = Drupal::service('security_review.checklist');
-
-  $security_review->setLastRun(time());
-  if ($success) {
-    if (!empty($results)) {
-      $checklist->storeResults($results);
-    }
-    drupal_set_message(t('Review complete'));
-  }
-  else {
-    // Show error information.
-    $error_operation = reset($operations);
-    $message = t(
-      'An error occurred while processing %error_operation with arguments: @arguments',
-      [
-        '%error_operation' => $error_operation[0],
-        '@arguments' => print_r($error_operation[1], TRUE),
-      ]
-    );
-    $security_review->log(NULL, $message, [], RfcLogLevel::ERROR);
-    drupal_set_message(t('The review did not store all results, please run again or check the logs for details.'));
-  }
-}
diff --git a/web/modules/contrib/security_review/security_review.permissions.yml b/web/modules/contrib/security_review/security_review.permissions.yml
deleted file mode 100644 (file)
index 9b1ea80..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-access security review list:
-  title: 'Access security review pages'
-  description: 'View security review checks and output. Give only to trusted users.'
-
-run security checks:
-  title: 'Run security review checks'
-  description: 'Run the security review checks.'
diff --git a/web/modules/contrib/security_review/security_review.routing.yml b/web/modules/contrib/security_review/security_review.routing.yml
deleted file mode 100644 (file)
index e7433e0..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-security_review:
-  path: 'admin/reports/security-review'
-  defaults:
-    _controller: '\Drupal\security_review\Controller\ChecklistController::index'
-  requirements:
-    _permission: 'access security review list'
-
-security_review.help:
-  path: 'admin/reports/security-review/help/{namespace}/{title}'
-  defaults:
-    _controller: '\Drupal\security_review\Controller\HelpController::index'
-    namespace: ~
-    title: ~
-  requirements:
-    _permission: 'access security review list'
-
-security_review.settings:
-  path: 'admin/config/security-review'
-  defaults:
-    _form: '\Drupal\security_review\Form\SettingsForm'
-  requirements:
-    _permission: 'access security review list'
-
-security_review.toggle:
-  path: 'admin/reports/security-review/toggle/{check_id}'
-  defaults:
-    _controller: '\Drupal\security_review\Controller\ToggleController::index'
-  requirements:
-    _permission: 'access security review list'
diff --git a/web/modules/contrib/security_review/security_review.services.yml b/web/modules/contrib/security_review/security_review.services.yml
deleted file mode 100644 (file)
index 43827d7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-services:
-  security_review:
-    class: Drupal\security_review\SecurityReview
-    arguments: ['@config.factory', '@state', '@module_handler', '@current_user']
-
-  security_review.checklist:
-    class: Drupal\security_review\Checklist
-    arguments: ['@security_review', '@module_handler', '@current_user']
-
-  security_review.security:
-    class: Drupal\security_review\Security
-    arguments: ['@security_review', '@module_handler', '@config.factory', '@kernel']
diff --git a/web/modules/contrib/security_review/src/Check.php b/web/modules/contrib/security_review/src/Check.php
deleted file mode 100644 (file)
index df18deb..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\user\Entity\User;
-
-/**
- * Defines a security check.
- */
-abstract class Check {
-
-  use DependencySerializationTrait;
-  use StringTranslationTrait;
-
-  /**
-   * The configuration storage for this check.
-   *
-   * @var \Drupal\Core\Config\Config $config
-   */
-  protected $config;
-
-  /**
-   * The service container.
-   *
-   * @var \Symfony\Component\DependencyInjection\ContainerInterface
-   */
-  protected $container;
-
-  /**
-   * Settings handler for this check.
-   *
-   * @var \Drupal\security_review\CheckSettingsInterface $settings
-   */
-  protected $settings;
-
-  /**
-   * The State system.
-   *
-   * @var \Drupal\Core\State\State
-   */
-  protected $state;
-
-  /**
-   * The check's prefix in the State system.
-   *
-   * @var string
-   */
-  protected $statePrefix;
-
-  /**
-   * Initializes the configuration storage and the settings handler.
-   */
-  public function __construct() {
-    $this->container = \Drupal::getContainer();
-
-    $this->config = $this->configFactory()
-      ->getEditable('security_review.check.' . $this->id());
-    $this->settings = new CheckSettings($this, $this->config);
-    $this->state = $this->container->get('state');
-    $this->statePrefix = 'security_review.check.' . $this->id() . '.';
-
-    // Set check ID in config.
-    if ($this->config->get('id') != $this->id()) {
-      $this->config->set('id', $this->id());
-      $this->config->save();
-    }
-  }
-
-  /**
-   * Returns the namespace of the check.
-   *
-   * Usually it's the same as the module's name.
-   *
-   * Naming rules (if overridden):
-   *   - All characters should be lowerspace.
-   *   - Use characters only from the english alphabet.
-   *   - Don't use spaces (use "_" instead).
-   *
-   * @return string
-   *   Machine namespace of the check.
-   */
-  public function getMachineNamespace() {
-    $namespace = strtolower($this->getNamespace());
-    $namespace = preg_replace("/[^a-z0-9 ]/", '', $namespace);
-    $namespace = str_replace(' ', '_', $namespace);
-
-    return $namespace;
-  }
-
-  /**
-   * Returns the namespace of the check.
-   *
-   * Usually it's the same as the module's name.
-   *
-   * @return string
-   *   Human-readable namespace of the check.
-   */
-  public abstract function getNamespace();
-
-  /**
-   * Returns the machine name of the check.
-   *
-   * Naming rules (if overridden):
-   *   - All characters should be lowerspace.
-   *   - Use characters only from the english alphabet.
-   *   - Don't use spaces (use "_" instead).
-   *
-   * @return string
-   *   ID of check.
-   */
-  public function getMachineTitle() {
-    $title = strtolower($this->getTitle());
-    $title = preg_replace("/[^a-z0-9 ]/", '', $title);
-    $title = str_replace(' ', '_', $title);
-
-    return $title;
-  }
-
-  /**
-   * Returns the human-readable title of the check.
-   *
-   * @return string
-   *   Title of check.
-   */
-  public abstract function getTitle();
-
-  /**
-   * Returns the identifier constructed using the namespace and title values.
-   *
-   * @return string
-   *   Unique identifier of the check.
-   */
-  public final function id() {
-    return $this->getMachineNamespace() . '-' . $this->getMachineTitle();
-  }
-
-  /**
-   * Returns whether the findings should be stored or reproduced when needed.
-   *
-   * The only case when this function should return false is if the check can
-   * generate a lot of findings (like the File permissions check for example).
-   * Turning this off for checks that don't generate findings at all or just a
-   * few of them actually means more overhead as the check has to be re-run
-   * in order to get its last result.
-   *
-   * @return bool
-   *   Boolean indicating whether findings will be stored.
-   */
-  public function storesFindings() {
-    return TRUE;
-  }
-
-  /**
-   * Returns the check-specific settings' handler.
-   *
-   * @return \Drupal\security_review\CheckSettingsInterface
-   *   The settings interface of the check.
-   */
-  public function settings() {
-    return $this->settings;
-  }
-
-  /**
-   * The actual procedure of carrying out the check.
-   *
-   * @return \Drupal\security_review\CheckResult
-   *   The result of running the check.
-   */
-  public abstract function run();
-
-  /**
-   * Same as run(), but used in CLI context such as Drush.
-   *
-   * @return \Drupal\security_review\CheckResult
-   *   The result of running the check.
-   */
-  public function runCli() {
-    return $this->run();
-  }
-
-  /**
-   * Returns the check-specific help page.
-   *
-   * @return array
-   *   The render array of the check's help page.
-   */
-  public abstract function help();
-
-  /**
-   * Returns the evaluation page of a result.
-   *
-   * Usually this is a list of the findings and an explanation.
-   *
-   * @param \Drupal\security_review\CheckResult $result
-   *   The check result to evaluate.
-   *
-   * @return array
-   *   The render array of the evaluation page.
-   */
-  public function evaluate(CheckResult $result) {
-    return [];
-  }
-
-  /**
-   * Evaluates a CheckResult and returns a plaintext output.
-   *
-   * @param \Drupal\security_review\CheckResult $result
-   *   The check result to evaluate.
-   *
-   * @return string
-   *   The evaluation string.
-   */
-  public function evaluatePlain(CheckResult $result) {
-    return '';
-  }
-
-  /**
-   * Converts a result integer to a human-readable result message.
-   *
-   * @param int $result_const
-   *   The result integer.
-   *
-   * @return string
-   *   The human-readable result message.
-   */
-  public abstract function getMessage($result_const);
-
-  /**
-   * Returns the last stored result of the check.
-   *
-   * Returns null if no results have been stored yet.
-   *
-   * @param bool $get_findings
-   *   Whether to get the findings too.
-   *
-   * @return \Drupal\security_review\CheckResult|null
-   *   The last stored result (or null).
-   */
-  public function lastResult($get_findings = FALSE) {
-    // Get stored data from State system.
-    $state_prefix = $this->statePrefix . 'last_result.';
-    $result = $this->state->get($state_prefix . 'result');
-    if ($get_findings) {
-      $findings = $this->state->get($state_prefix . 'findings');
-    }
-    else {
-      $findings = [];
-    }
-    $time = $this->state->get($state_prefix . 'time');
-    // Force boolean value.
-    $visible = $this->state->get($state_prefix . 'visible') == TRUE;
-
-    // Check validity of stored data.
-    $valid_result = is_int($result)
-      && $result >= CheckResult::SUCCESS
-      && $result <= CheckResult::INFO;
-    $valid_findings = is_array($findings);
-    $valid_time = is_int($time) && $time > 0;
-
-    // If invalid, return NULL.
-    if (!$valid_result || !$valid_findings || !$valid_time) {
-      return NULL;
-    }
-
-    // Construct the CheckResult.
-    $last_result = new CheckResult($this, $result, $findings, $visible, $time);
-
-    // Do a check run for acquiring findings if required.
-    if ($get_findings && !$this->storesFindings()) {
-      // Run the check to get the findings.
-      $fresh_result = $this->run();
-
-      // If it malfunctioned return the last known good result.
-      if (!($fresh_result instanceof CheckResult)) {
-        return $last_result;
-      }
-
-      if ($fresh_result->result() != $last_result->result()) {
-        // If the result is not the same store the new result and return it.
-        $this->storeResult($fresh_result);
-        $this->securityReview()->logCheckResult($fresh_result);
-        return $fresh_result;
-      }
-      else {
-        // Else return the old result with the fresh one's findings.
-        return CheckResult::combine($last_result, $fresh_result);
-      }
-    }
-
-    return $last_result;
-  }
-
-  /**
-   * Returns the timestamp the check was last run.
-   *
-   * Returns 0 if it has not been run yet.
-   *
-   * @return int
-   *   The timestamp of the last stored result.
-   */
-  public function lastRun() {
-    $last_result_time = $this->state
-      ->get($this->statePrefix . 'last_result.time');
-
-    if (!is_int($last_result_time)) {
-      return 0;
-    }
-    return $last_result_time;
-  }
-
-  /**
-   * Returns whether the check is skipped. Checks are not skipped by default.
-   *
-   * @return bool
-   *   Boolean indicating whether the check is skipped.
-   */
-  public function isSkipped() {
-    $is_skipped = $this->config->get('skipped');
-
-    if (!is_bool($is_skipped)) {
-      return FALSE;
-    }
-    return $is_skipped;
-  }
-
-  /**
-   * Returns the user the check was skipped by.
-   *
-   * Returns null if it hasn't been skipped yet or the user that skipped the
-   * check is not valid anymore.
-   *
-   * @return \Drupal\user\Entity\User|null
-   *   The user the check was last skipped by (or null).
-   */
-  public function skippedBy() {
-    $skipped_by = $this->config->get('skipped_by');
-
-    if (!is_int($skipped_by)) {
-      return NULL;
-    }
-    return User::load($skipped_by);
-  }
-
-  /**
-   * Returns the timestamp the check was last skipped on.
-   *
-   * Returns 0 if it hasn't been skipped yet.
-   *
-   * @return int
-   *   The UNIX timestamp the check was last skipped on (or 0).
-   */
-  public function skippedOn() {
-    $skipped_on = $this->config->get('skipped_on');
-
-    if (!is_int($skipped_on)) {
-      return 0;
-    }
-    return $skipped_on;
-  }
-
-  /**
-   * Enables the check. Has no effect if the check was not skipped.
-   */
-  public function enable() {
-    if ($this->isSkipped()) {
-      $this->config->set('skipped', FALSE);
-      $this->config->save();
-
-      // Log.
-      $context = ['@name' => $this->getTitle()];
-      $this->securityReview()->log($this, '@name check no longer skipped', $context, RfcLogLevel::NOTICE);
-    }
-  }
-
-  /**
-   * Marks the check as skipped.
-   *
-   * It still can be ran manually, but will remain skipped on the Run & Review
-   * page.
-   */
-  public function skip() {
-    if (!$this->isSkipped()) {
-      // Store skip data.
-      $this->config->set('skipped', TRUE);
-      $this->config->set('skipped_by', $this->currentUser()->id());
-      $this->config->set('skipped_on', time());
-      $this->config->save();
-
-      // Log.
-      $context = ['@name' => $this->getTitle()];
-      $this->securityReview()->log($this, '@name check skipped', $context, RfcLogLevel::NOTICE);
-    }
-  }
-
-  /**
-   * Stores a result in the state system.
-   *
-   * @param \Drupal\security_review\CheckResult $result
-   *   The result to store.
-   */
-  public function storeResult(CheckResult $result) {
-    if ($result == NULL) {
-      $context = [
-        '@reviewcheck' => $this->getTitle(),
-        '@namespace' => $this->getNamespace(),
-      ];
-      $this->securityReview()->log($this, 'Unable to store check @reviewcheck for @namespace', $context, RfcLogLevel::CRITICAL);
-      return;
-    }
-
-    $findings = $this->storesFindings() ? $result->findings() : [];
-    $this->state->setMultiple([
-      $this->statePrefix . 'last_result.result' => $result->result(),
-      $this->statePrefix . 'last_result.time' => $result->time(),
-      $this->statePrefix . 'last_result.visible' => $result->isVisible(),
-      $this->statePrefix . 'last_result.findings' => $findings,
-    ]);
-  }
-
-  /**
-   * Creates a new CheckResult for this Check.
-   *
-   * @param int $result
-   *   The result integer (see the constants defined in CheckResult).
-   * @param array $findings
-   *   The findings.
-   * @param bool $visible
-   *   The visibility of the result.
-   * @param int $time
-   *   The time the test was run.
-   *
-   * @return \Drupal\security_review\CheckResult
-   *   The created CheckResult.
-   */
-  public function createResult($result, array $findings = [], $visible = TRUE, $time = NULL) {
-    return new CheckResult($this, $result, $findings, $visible, $time);
-  }
-
-  /**
-   * Returns the Security Review Checklist service.
-   *
-   * @return \Drupal\security_review\Checklist
-   *   Security Review's Checklist service.
-   */
-  protected function checklist() {
-    return $this->container->get('security_review.checklist');
-  }
-
-  /**
-   * Returns the Config factory.
-   *
-   * @return \Drupal\Core\Config\ConfigFactory
-   *   Config factory.
-   */
-  protected function configFactory() {
-    return $this->container->get('config.factory');
-  }
-
-  /**
-   * Returns the service container.
-   *
-   * @return \Symfony\Component\DependencyInjection\ContainerInterface
-   *   Service container.
-   */
-  protected function container() {
-    return $this->container;
-  }
-
-  /**
-   * Returns the current Drupal user.
-   *
-   * @return \Drupal\Core\Session\AccountProxy
-   *   Current Drupal user.
-   */
-  protected function currentUser() {
-    return $this->container->get('current_user');
-  }
-
-  /**
-   * Returns the database connection.
-   *
-   * @return \Drupal\Core\Database\Connection
-   *   Database connection.
-   */
-  protected function database() {
-    return $this->container->get('database');
-  }
-
-  /**
-   * Returns the entity manager.
-   *
-   * @return \Drupal\Core\Entity\EntityManagerInterface
-   *   Entity manager.
-   */
-  protected function entityManager() {
-    return $this->container->get('entity.manager');
-  }
-
-  /**
-   * Returns the Drupal Kernel.
-   *
-   * @return \Drupal\Core\DrupalKernel
-   *   Drupal Kernel.
-   */
-  protected function kernel() {
-    return $this->container->get('kernel');
-  }
-
-  /**
-   * Returns the module handler.
-   *
-   * @return \Drupal\Core\Extension\ModuleHandler
-   *   Module handler.
-   */
-  protected function moduleHandler() {
-    return $this->container->get('module_handler');
-  }
-
-  /**
-   * Returns the Security Review Security service.
-   *
-   * @return \Drupal\security_review\Security
-   *   Security Review's Security service.
-   */
-  protected function security() {
-    return $this->container->get('security_review.security');
-  }
-
-  /**
-   * Returns the Security Review service.
-   *
-   * @return \Drupal\security_review\SecurityReview
-   *   Security Review service.
-   */
-  protected function securityReview() {
-    return $this->container->get('security_review');
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/CheckResult.php b/web/modules/contrib/security_review/src/CheckResult.php
deleted file mode 100644 (file)
index 8307a8b..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-/**
- * Used to define the result of a Check.
- */
-class CheckResult {
-
-  const SUCCESS = 0;
-  const FAIL = 1;
-  const WARN = 2;
-  const INFO = 3;
-
-  /**
-   * Stores the parent Check.
-   *
-   * @var \Drupal\security_review\Check $check
-   */
-  private $check;
-
-  /**
-   * Stores the outcome of the check.
-   *
-   * @var int $result
-   */
-  private $result;
-
-  /**
-   * Stores findings.
-   *
-   * @var array $findings
-   */
-  private $findings;
-
-  /**
-   * Stores the timestamp of the check run.
-   *
-   * @var int $time
-   */
-  private $time;
-
-  /**
-   * Whether the result should be shown on the UI.
-   *
-   * @var bool $visible
-   */
-  private $visible;
-
-  /**
-   * Constructs an immutable CheckResult.
-   *
-   * @param \Drupal\security_review\Check $check
-   *   The Check that created this result.
-   * @param int $result
-   *   The result integer (see the constants defined above).
-   * @param array $findings
-   *   The findings.
-   * @param int $time
-   *   The timestamp of the check run.
-   * @param bool $visible
-   *   The visibility of the result.
-   */
-  public function __construct(Check $check, $result, array $findings, $visible = TRUE, $time = NULL) {
-    // Set the parent check.
-    $this->check = $check;
-
-    // Set the result value.
-    $result = intval($result);
-    if ($result < self::SUCCESS || $result > self::INFO) {
-      $result = self::INFO;
-    }
-    $this->result = $result;
-
-    // Set the findings.
-    $this->findings = $findings;
-
-    // Set the visibility.
-    $this->visible = $visible;
-
-    // Set the timestamp.
-    if (!is_int($time)) {
-      $this->time = time();
-    }
-    else {
-      $this->time = intval($time);
-    }
-  }
-
-  /**
-   * Combines two CheckResults.
-   *
-   * Combines two CheckResults and returns a new one with the old one's fields
-   * except for the findings which are copied from the fresh result.
-   *
-   * @param \Drupal\security_review\CheckResult $old
-   *   The old result to clone.
-   * @param \Drupal\security_review\CheckResult $fresh
-   *   The new result to copy the findings from.
-   *
-   * @return \Drupal\security_review\CheckResult
-   *   The combined result.
-   */
-  public static function combine(CheckResult $old, CheckResult $fresh) {
-    return new CheckResult($old->check, $old->result, $fresh->findings, $old->visible, $old->time);
-  }
-
-  /**
-   * Returns the parent Check.
-   *
-   * @return \Drupal\security_review\Check
-   *   The Check that created this result.
-   */
-  public function check() {
-    return $this->check;
-  }
-
-  /**
-   * Returns the outcome of the check.
-   *
-   * @return int
-   *   The result integer.
-   */
-  public function result() {
-    return $this->result;
-  }
-
-  /**
-   * Returns the findings.
-   *
-   * @return array
-   *   The findings. Contents of this depends on the actual check.
-   */
-  public function findings() {
-    return $this->findings;
-  }
-
-  /**
-   * Returns the timestamp.
-   *
-   * @return int
-   *   The timestamp the result was created on.
-   */
-  public function time() {
-    return $this->time;
-  }
-
-  /**
-   * Returns the visibility of the result.
-   *
-   * @return bool
-   *   Whether the result should be shown on the UI.
-   */
-  public function isVisible() {
-    return $this->visible;
-  }
-
-  /**
-   * Returns the result message.
-   *
-   * @return string
-   *   The result message for this result.
-   */
-  public function resultMessage() {
-    return $this->check->getMessage($this->result);
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/CheckSettings.php b/web/modules/contrib/security_review/src/CheckSettings.php
deleted file mode 100644 (file)
index 5e9fce9..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-use Drupal\Core\Config\Config;
-
-/**
- * Defines the default implementation of CheckSettingsInterface.
- */
-class CheckSettings implements CheckSettingsInterface {
-
-  /**
-   * The parent check.
-   *
-   * @var \Drupal\security_review\Check
-   */
-  protected $check;
-
-  /**
-   * The configuration storage of the parent Check.
-   *
-   * @var \Drupal\Core\Config\Config $config
-   */
-  protected $config;
-
-  /**
-   * Creates a CheckSettings instance.
-   *
-   * @param \Drupal\security_review\Check $check
-   *   The parent Check.
-   * @param \Drupal\Core\Config\Config $config
-   *   The parent Check's configuration.
-   */
-  public function __construct(Check $check, Config &$config) {
-    $this->check = $check;
-    $this->config = $config;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function get($key, $default_value = NULL) {
-    $value = $this->config->get('settings.' . $key);
-
-    if ($value == NULL) {
-      return $default_value;
-    }
-    return $value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function set($key, $value) {
-    $this->config->set('settings.' . $key, $value);
-    $this->config->save();
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm() {
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, array $values) {
-    // Validation is optional.
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, array $values) {
-    // Handle submission.
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/CheckSettings/TrustedHostSettings.php b/web/modules/contrib/security_review/src/CheckSettings/TrustedHostSettings.php
deleted file mode 100644 (file)
index feb95bb..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-namespace Drupal\security_review\CheckSettings;
-
-use Drupal\security_review\CheckSettings;
-
-/**
- * Provides the settings form for the TrustedHosts check.
- */
-class TrustedHostSettings extends CheckSettings {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm() {
-    $form = [];
-    $form['method'] = [
-      '#type' => 'radios',
-      '#title' => t('Check method'),
-      '#description' => t('Detecting the $base_url in settings.php can be done via PHP tokenization (recommended) or including the file. Note that if you have custom functionality in your settings.php it will be executed if the file is included. Including the file can result in a more accurate $base_url check if you wrap the setting in conditional statements.'),
-      '#options' => [
-        'token' => t('Tokenize settings.php (recommended)'),
-        'include' => t('Include settings.php'),
-      ],
-      '#default_value' => $this->get('method', 'token'),
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, array $values) {
-    $this->set('method', $values['method']);
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/CheckSettingsInterface.php b/web/modules/contrib/security_review/src/CheckSettingsInterface.php
deleted file mode 100644 (file)
index 146e12c..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-/**
- * Interface for check-specific settings and forms for altering them.
- */
-interface CheckSettingsInterface {
-
-  /**
-   * Gets a check-specific setting value identified by $key.
-   *
-   * @param string $key
-   *   The key.
-   * @param mixed $default_value
-   *   Default value to return in case $key does not exist.
-   *
-   * @return mixed
-   *   The value of the stored setting.
-   */
-  public function get($key, $default_value);
-
-  /**
-   * Sets a check-specific setting value identified by $key.
-   *
-   * @param string $key
-   *   The key.
-   * @param mixed $value
-   *   The new value.
-   *
-   * @return CheckSettingsInterface
-   *   Returns itself.
-   */
-  public function set($key, $value);
-
-  /**
-   * Form constructor.
-   *
-   * @return array
-   *   The form structure.
-   */
-  public function buildForm();
-
-  /**
-   * Form validation handler.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param array $values
-   *   The current values of the form.
-   */
-  public function validateForm(array &$form, array $values);
-
-  /**
-   * Form submission handler.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param array $values
-   *   The current values of the form.
-   */
-  public function submitForm(array &$form, array $values);
-
-}
diff --git a/web/modules/contrib/security_review/src/Checklist.php b/web/modules/contrib/security_review/src/Checklist.php
deleted file mode 100644 (file)
index 0c9aca0..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-use Drupal\Core\Access\AccessException;
-use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Session\AccountProxyInterface;
-
-/**
- * Contains static functions for handling checks throughout every module.
- */
-class Checklist {
-
-  use DependencySerializationTrait;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The security_review service.
-   *
-   * @var \Drupal\security_review\SecurityReview
-   */
-  protected $securityReview;
-
-  /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * Constructs a Checklist instance.
-   *
-   * @param \Drupal\security_review\SecurityReview $security_review
-   *   The SecurityReview service.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
-   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
-   *   The current user.
-   */
-  public function __construct(SecurityReview $security_review, ModuleHandlerInterface $module_handler, AccountProxyInterface $current_user) {
-    $this->securityReview = $security_review;
-    $this->moduleHandler = $module_handler;
-    $this->currentUser = $current_user;
-  }
-
-  /**
-   * Array of cached Checks.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  private static $cachedChecks = [];
-
-  /**
-   * Clears the cached checks.
-   */
-  public static function clearCache() {
-    static::$cachedChecks = [];
-  }
-
-  /**
-   * Returns every Check.
-   *
-   * @return \Drupal\security_review\Check[]
-   *   Array of Checks.
-   */
-  public function getChecks() {
-    $checks = &static::$cachedChecks;
-    if (!empty($checks)) {
-      return $checks;
-    }
-
-    // Get checks.
-    $raw_checks = $this->moduleHandler->invokeAll('security_review_checks');
-
-    // Filter invalid checks.
-    $checks = [];
-    foreach ($raw_checks as $raw_check) {
-      if ($raw_check instanceof Check) {
-        $checks[] = $raw_check;
-      }
-    }
-
-    // Sort the checks.
-    usort($checks, [$this, 'compareChecks']);
-
-    return $checks;
-  }
-
-  /**
-   * Returns the enabled Checks.
-   *
-   * @return \Drupal\security_review\Check[]
-   *   Array of enabled Checks.
-   */
-  public function getEnabledChecks() {
-    $enabled = [];
-
-    foreach (static::getChecks() as $check) {
-      if (!$check->isSkipped()) {
-        $enabled[] = $check;
-      }
-    }
-
-    return $enabled;
-  }
-
-  /**
-   * Groups an array of checks by their namespaces.
-   *
-   * @param \Drupal\security_review\Check[] $checks
-   *   The array of Checks to group.
-   *
-   * @return array
-   *   Array containing Checks grouped by their namespaces.
-   */
-  public function groupChecksByNamespace(array $checks) {
-    $output = [];
-
-    foreach ($checks as $check) {
-      $output[$check->getMachineNamespace()][] = $check;
-    }
-
-    return $output;
-  }
-
-  /**
-   * Runs enabled checks and stores their results.
-   */
-  public function runChecklist() {
-    if ($this->currentUser->hasPermission('run security checks')) {
-      $checks = $this->getEnabledChecks();
-      $results = $this->runChecks($checks);
-      $this->storeResults($results);
-      $this->securityReview->setLastRun(time());
-    }
-    else {
-      throw new AccessException();
-    }
-  }
-
-  /**
-   * Runs an array of checks.
-   *
-   * @param \Drupal\security_review\Check[] $checks
-   *   The array of Checks to run.
-   * @param bool $cli
-   *   Whether to call runCli() instead of run().
-   *
-   * @return \Drupal\security_review\CheckResult[]
-   *   The array of CheckResults generated.
-   */
-  public function runChecks(array $checks, $cli = FALSE) {
-    $results = [];
-
-    foreach ($checks as $check) {
-      if ($cli) {
-        $result = $check->runCli();
-      }
-      else {
-        $result = $check->run();
-      }
-      $this->securityReview->logCheckResult($result);
-      $results[] = $result;
-    }
-
-    return $results;
-  }
-
-  /**
-   * Stores an array of CheckResults.
-   *
-   * @param \Drupal\security_review\CheckResult[] $results
-   *   The CheckResults to store.
-   */
-  public function storeResults(array $results) {
-    foreach ($results as $result) {
-      $result->check()->storeResult($result);
-    }
-  }
-
-  /**
-   * Finds a check by its namespace and title.
-   *
-   * @param string $namespace
-   *   The machine namespace of the requested check.
-   * @param string $title
-   *   The machine title of the requested check.
-   *
-   * @return null|\Drupal\security_review\Check
-   *   The Check or null if it doesn't exist.
-   */
-  public function getCheck($namespace, $title) {
-    foreach (static::getChecks() as $check) {
-      $same_namespace = $check->getMachineNamespace() == $namespace;
-      $same_title = $check->getMachineTitle() == $title;
-      if ($same_namespace && $same_title) {
-        return $check;
-      }
-    }
-
-    return NULL;
-  }
-
-  /**
-   * Finds a Check by its id.
-   *
-   * @param string $id
-   *   The machine namespace of the requested check.
-   *
-   * @return null|\Drupal\security_review\Check
-   *   The Check or null if it doesn't exist.
-   */
-  public function getCheckById($id) {
-    foreach (static::getChecks() as $check) {
-      if ($check->id() == $id) {
-        return $check;
-      }
-    }
-
-    return NULL;
-  }
-
-  /**
-   * Helper function for sorting checks.
-   *
-   * @param \Drupal\security_review\Check $a
-   *   Check A.
-   * @param \Drupal\security_review\Check $b
-   *   Check B.
-   *
-   * @return int
-   *   The comparison's result.
-   */
-  public function compareChecks(Check $a, Check $b) {
-    // If one comes from security_review and the other doesn't, prefer the one
-    // with the security_review namespace.
-    $a_is_local = $a->getMachineNamespace() == 'security_review';
-    $b_is_local = $b->getMachineNamespace() == 'security_review';
-    if ($a_is_local && !$b_is_local) {
-      return -1;
-    }
-    elseif (!$a_is_local && $b_is_local) {
-      return 1;
-    }
-    else {
-      if ($a->getNamespace() == $b->getNamespace()) {
-        // If the namespaces match, sort by title.
-        return strcmp($a->getTitle(), $b->getTitle());
-      }
-      else {
-        // If the namespaces don't mach, sort by namespace.
-        return strcmp($a->getNamespace(), $b->getNamespace());
-      }
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/AdminPermissions.php b/web/modules/contrib/security_review/src/Checks/AdminPermissions.php
deleted file mode 100644 (file)
index 5551f32..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-use Drupal\user\Entity\Role;
-
-/**
- * Checks whether untrusted roles have restricted permissions.
- */
-class AdminPermissions extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Drupal permissions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMachineTitle() {
-    return 'admin_permissions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    // Get every permission.
-    $all_permissions = $this->security()->permissions(TRUE);
-    $all_permission_strings = array_keys($all_permissions);
-
-    // Get permissions for untrusted roles.
-    $untrusted_permissions = $this->security()->untrustedPermissions(TRUE);
-    foreach ($untrusted_permissions as $rid => $permissions) {
-      $intersect = array_intersect($all_permission_strings, $permissions);
-      foreach ($intersect as $permission) {
-        if (isset($all_permissions[$permission]['restrict access'])) {
-          $findings[$rid][] = $permission;
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t("Drupal's permission system is extensive and allows for varying degrees of control. Certain permissions would allow a user total control, or the ability to escalate their control, over your site and should only be granted to trusted users.");
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Admin and trusted Drupal permissions'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $output = [];
-
-    foreach ($result->findings() as $rid => $permissions) {
-      $role = Role::load($rid);
-      /** @var Role $role */
-      $paragraphs = [];
-      $paragraphs[] = $this->t(
-        "@role has the following restricted permissions:",
-        [
-          '@role' => Link::createFromRoute(
-            $role->label(),
-            'entity.user_role.edit_permissions_form',
-            ['user_role' => $role->id()]
-          )->toString(),
-        ]
-      );
-
-      $output[] = [
-        '#theme' => 'check_evaluation',
-        '#paragraphs' => $paragraphs,
-        '#items' => $permissions,
-      ];
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $output = '';
-
-    foreach ($result->findings() as $rid => $permissions) {
-      $role = Role::load($rid);
-      /** @var Role $role */
-
-      $output .= $this->t(
-        '@role has @permissions',
-        [
-          '@role' => $role->label(),
-          '@permissions' => implode(', ', $permissions),
-        ]
-      );
-      $output .= "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Untrusted roles do not have administrative or trusted Drupal permissions.');
-
-      case CheckResult::FAIL:
-        return $this->t('Untrusted roles have been granted administrative or trusted Drupal permissions.');
-
-      default:
-        return $this->t("Unexpected result.");
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/ErrorReporting.php b/web/modules/contrib/security_review/src/Checks/ErrorReporting.php
deleted file mode 100644 (file)
index 34dd765..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Defines a security check that checks the error reporting setting.
- */
-class ErrorReporting extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Error reporting';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    // Get the error level.
-    $error_level = $this->configFactory()->get('system.logging')
-      ->get('error_level');
-
-    // Determine the result.
-    if (is_null($error_level) || $error_level != 'hide') {
-      $result = CheckResult::FAIL;
-    }
-    else {
-      $result = CheckResult::SUCCESS;
-    }
-
-    return $this->createResult($result, ['level' => $error_level]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('As a form of hardening your site you should avoid information disclosure. Drupal by default prints errors to the screen and writes them to the log. Error messages disclose the full path to the file where the error occurred.');
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Error reporting'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    if ($result->result() == CheckResult::SUCCESS) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('You have error reporting set to both the screen and the log.');
-    $paragraphs[] = Link::createFromRoute(
-      $this->t('Alter error reporting settings.'),
-      'system.logging_settings'
-    );
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => [],
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    if ($result->result() == CheckResult::SUCCESS) {
-      return '';
-    }
-
-    if (isset($result->findings()['level'])) {
-      return $this->t('Error level: @level', [
-        '@level' => $result->findings()['level'],
-      ]);
-    }
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Error reporting set to log only.');
-
-      case CheckResult::FAIL:
-        return $this->t('Errors are written to the screen.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/ExecutablePhp.php b/web/modules/contrib/security_review/src/Checks/ExecutablePhp.php
deleted file mode 100644 (file)
index dd93617..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Component\PhpStorage\FileStorage;
-use Drupal\Core\StreamWrapper\PublicStream;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-use GuzzleHttp\Exception\RequestException;
-
-/**
- * Checks if PHP files written to the files directory can be executed.
- */
-class ExecutablePhp extends Check {
-
-  /**
-   * Drupal's HTTP Client.
-   *
-   * @var \Drupal\Core\Http\Client
-   */
-  protected $httpClient;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct() {
-    parent::__construct();
-    $this->httpClient = $this->container->get('http_client');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Executable PHP';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run($cli = FALSE) {
-    global $base_url;
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    // Set up test file data.
-    $message = 'Security review test ' . date('Ymdhis');
-    $content = "<?php\necho '" . $message . "';";
-    $file_path = PublicStream::basePath() . '/security_review_test.php';
-
-    // Create the test file.
-    if ($test_file = @fopen('./' . $file_path, 'w')) {
-      fwrite($test_file, $content);
-      fclose($test_file);
-    }
-
-    // Try to access the test file.
-    try {
-      $response = $this->httpClient->get($base_url . '/' . $file_path);
-      if ($response->getStatusCode() == 200 && $response->getBody() === $message) {
-        $result = CheckResult::FAIL;
-        $findings[] = 'executable_php';
-      }
-    }
-    catch (RequestException $e) {
-      // Access was denied to the file.
-    }
-
-    // Remove the test file.
-    if (file_exists('./' . $file_path)) {
-      @unlink('./' . $file_path);
-    }
-
-    // Check for presence of the .htaccess file and if the contents are correct.
-    $htaccess_path = PublicStream::basePath() . '/.htaccess';
-    if (!file_exists($htaccess_path)) {
-      $result = CheckResult::FAIL;
-      $findings[] = 'missing_htaccess';
-    }
-    else {
-      // Check whether the contents of .htaccess are correct.
-      $contents = file_get_contents($htaccess_path);
-      $expected = FileStorage::htaccessLines(FALSE);
-
-      // Trim each line separately then put them back together.
-      $contents = implode("\n", array_map('trim', explode("\n", trim($contents))));
-      $expected = implode("\n", array_map('trim', explode("\n", trim($expected))));
-
-      if ($contents !== $expected) {
-        $result = CheckResult::FAIL;
-        $findings[] = 'incorrect_htaccess';
-      }
-
-      // Check whether .htaccess is writable.
-      if (!$cli) {
-        $writable_htaccess = is_writable($htaccess_path);
-      }
-      else {
-        $writable = $this->security()->findWritableFiles([$htaccess_path], TRUE);
-        $writable_htaccess = !empty($writable);
-      }
-
-      if ($writable_htaccess) {
-        $findings[] = 'writable_htaccess';
-        if ($result !== CheckResult::FAIL) {
-          $result = CheckResult::WARN;
-        }
-      }
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function runCli() {
-    return $this->run(TRUE);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The Drupal files directory is for user-uploaded files and by default provides some protection against a malicious user executing arbitrary PHP code against your site.');
-    $paragraphs[] = $this->t('Read more about the <a href="https://drupal.org/node/615888">risk of PHP code execution on Drupal.org</a>.');
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Executable PHP in files directory'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $paragraphs = [];
-    foreach ($result->findings() as $label) {
-      switch ($label) {
-        case 'executable_php':
-          $paragraphs[] = $this->t('Security Review was able to execute a PHP file written to your files directory.');
-          break;
-
-        case 'missing_htaccess':
-          $directory = PublicStream::basePath();
-          $paragraphs[] = $this->t("The .htaccess file is missing from the files directory at @path", ['@path' => $directory]);
-          $paragraphs[] = $this->t("Note, if you are using a webserver other than Apache you should consult your server's documentation on how to limit the execution of PHP scripts in this directory.");
-          break;
-
-        case 'incorrect_htaccess':
-          $paragraphs[] = $this->t("The .htaccess file exists but does not contain the correct content. It is possible it's been maliciously altered.");
-          break;
-
-        case 'writable_htaccess':
-          $paragraphs[] = $this->t("The .htaccess file is writable which poses a risk should a malicious user find a way to execute PHP code they could alter the .htaccess file to allow further PHP code execution.");
-          break;
-      }
-    }
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => [],
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $paragraphs = [];
-    $directory = PublicStream::basePath();
-    foreach ($result->findings() as $label) {
-      switch ($label) {
-        case 'executable_php':
-          $paragraphs[] = $this->t('PHP file executed in @path', ['@path' => $directory]);
-          break;
-
-        case 'missing_htaccess':
-          $paragraphs[] = $this->t('.htaccess is missing from @path', ['@path' => $directory]);
-          break;
-
-        case 'incorrect_htaccess':
-          $paragraphs[] = $this->t('.htaccess wrong content');
-          break;
-
-        case 'writable_htaccess':
-          $paragraphs[] = $this->t('.htaccess writable');
-          break;
-      }
-    }
-
-    return implode("\n", $paragraphs);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('PHP files in the Drupal files directory cannot be executed.');
-
-      case CheckResult::FAIL:
-        return $this->t('PHP files in the Drupal files directory can be executed.');
-
-      case CheckResult::WARN:
-        return $this->t('The .htaccess file in the files directory is writable.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/FailedLogins.php b/web/modules/contrib/security_review/src/Checks/FailedLogins.php
deleted file mode 100644 (file)
index 1286dfa..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Checks for abundant failed logins.
- */
-class FailedLogins extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Failed logins';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    // If dblog is not enabled return with hidden INFO.
-    if (!$this->moduleHandler()->moduleExists('dblog')) {
-      return $this->createResult(CheckResult::INFO, [], FALSE);
-    }
-
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-    $last_result = $this->lastResult();
-    $visible = FALSE;
-
-    // Prepare the query.
-    $query = $this->database()->select('watchdog', 'w');
-    $query->fields('w', [
-      'severity',
-      'type',
-      'timestamp',
-      'message',
-      'variables',
-      'hostname',
-    ]);
-    $query->condition('type', 'user')
-      ->condition('severity', RfcLogLevel::NOTICE)
-      ->condition('message', 'Login attempt failed from %ip.');
-    if ($last_result instanceof CheckResult) {
-      // Only check entries that got recorded since the last run of the check.
-      $query->condition('timestamp', $last_result->time(), '>=');
-    }
-
-    // Execute the query.
-    $db_result = $query->execute();
-
-    // Count the number of failed logins per IP.
-    $entries = [];
-    foreach ($db_result as $row) {
-      $ip = unserialize($row->variables)['%ip'];
-      $entry_for_ip = &$entries[$ip];
-
-      if (!isset($entry_for_ip)) {
-        $entry_for_ip = 0;
-      }
-      $entry_for_ip++;
-    }
-
-    // Filter the IPs with more than 10 failed logins.
-    if (!empty($entries)) {
-      foreach ($entries as $ip => $count) {
-        if ($count > 10) {
-          $findings[] = $ip;
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-      $visible = TRUE;
-    }
-
-    return $this->createResult($result, $findings, $visible);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('Failed login attempts from the same IP may be an artifact of a malicious user attempting to brute-force their way onto your site as an authenticated user to carry out nefarious deeds.');
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Abundant failed logins from the same IP'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The following IPs were observed with an abundance of failed login attempts.');
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $result->findings(),
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return '';
-    }
-
-    $output = $this->t('Suspicious IP addresses:') . ":\n";
-    foreach ($findings as $ip) {
-      $output .= "\t" . $ip . "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::FAIL:
-        return $this->t('Failed login attempts from the same IP. These may be a brute-force attack to gain access to your site.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/Field.php b/web/modules/contrib/security_review/src/Checks/Field.php
deleted file mode 100644 (file)
index b41bc85..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Entity\Entity;
-use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Checks for Javascript and PHP in submitted content.
- */
-class Field extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Content';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMachineTitle() {
-    return 'field';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    $field_types = [
-      'text_with_summary',
-      'text_long',
-    ];
-    $tags = [
-      'Javascript' => 'script',
-      'PHP' => '?php',
-    ];
-
-    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
-    $entity_type_manager = \Drupal::service('entity_type.manager');
-    /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
-    $field_manager = \Drupal::service('entity_field.manager');
-    foreach ($field_manager->getFieldMap() as $entity_type_id => $fields) {
-      $field_storage_definitions = $field_manager->getFieldStorageDefinitions($entity_type_id);
-      foreach ($fields as $field_name => $field) {
-        if (!isset($field_storage_definitions[$field_name])) {
-          continue;
-        }
-        $field_storage_definition = $field_storage_definitions[$field_name];
-        if (in_array($field_storage_definition->getType(), $field_types)) {
-          if ($field_storage_definition instanceof FieldStorageConfig) {
-            $table = $entity_type_id . '__' . $field_name;
-            $separator = '_';
-            $id = 'entity_id';
-          }
-          else {
-            $table = $entity_type_id . '_field_data';
-            $separator = '__';
-            $id = $entity_type_manager->getDefinition($entity_type_id)->getKey('id');
-          }
-          $rows = \Drupal::database()->select($table, 't')
-            ->fields('t')
-            ->execute()
-            ->fetchAll();
-          foreach ($rows as $row) {
-            foreach (array_keys($field_storage_definition->getSchema()['columns']) as $column) {
-              $column_name = $field_name . $separator . $column;
-              foreach ($tags as $vulnerability => $tag) {
-                if (strpos($row->{$column_name}, '<' . $tag) !== FALSE) {
-                  // Vulnerability found.
-                  $findings[$entity_type_id][$row->{$id}][$field_name][] = $vulnerability;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('Script and PHP code in content does not align with Drupal best practices and may be a vulnerability if an untrusted user is allowed to edit such content. It is recommended you remove such contents.');
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Dangerous tags in content'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The following items potentially have dangerous tags.');
-
-    $items = [];
-    foreach ($findings as $entity_type_id => $entities) {
-      foreach ($entities as $entity_id => $fields) {
-        $entity = $this->entityManager()
-          ->getStorage($entity_type_id)
-          ->load($entity_id);
-
-        foreach ($fields as $field => $finding) {
-          $items[] = $this->t(
-            '@vulnerabilities found in <em>@field</em> field of <a href=":url">@label</a>',
-            [
-              '@vulnerabilities' => implode(' and ', $finding),
-              '@field' => $field,
-              '@label' => $entity->label(),
-              ':url' => $this->getEntityLink($entity),
-            ]
-          );
-        }
-      }
-    }
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $items,
-    ];
-  }
-
-  /**
-   * Attempt to get a good link for the given entity.
-   *
-   * Falls back on a string with entity type id and id if no good link can
-   * be found.
-   *
-   * @param \Drupal\Core\Entity\Entity $entity
-   *   The entity.
-   *
-   * @return string
-   */
-  protected function getEntityLink(Entity $entity) {
-    try {
-      $url = $entity->toUrl('edit-form');
-    }
-    catch (UndefinedLinkTemplateException $e) {
-      $url = NULL;
-    }
-    if ($url === NULL) {
-      try {
-        $url = $entity->toUrl();
-      }
-      catch (UndefinedLinkTemplateException $e) {
-        $url = NULL;
-      }
-    }
-
-    return $url !== NULL ? $url->toString() : ($entity->getEntityTypeId() . ':' . $entity->id());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return '';
-    }
-
-    $output = '';
-    foreach ($findings as $entity_type_id => $entities) {
-      foreach ($entities as $entity_id => $fields) {
-        $entity = $this->entityManager()
-          ->getStorage($entity_type_id)
-          ->load($entity_id);
-
-        foreach ($fields as $field => $finding) {
-          $output .= "\t" . $this->t(
-              '@vulnerabilities in @field of :link',
-              [
-                '@vulnerabilities' => implode(' and ', $finding),
-                '@field' => $field,
-                ':link' => $this->getEntityLink($entity),
-              ]
-            ) . "\n";
-        }
-      }
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Dangerous tags were not found in any submitted content (fields).');
-
-      case CheckResult::FAIL:
-        return $this->t('Dangerous tags were found in submitted content (fields).');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/Field.php.rej b/web/modules/contrib/security_review/src/Checks/Field.php.rej
deleted file mode 100644 (file)
index a2413ef..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
---- src/Checks/Field.php
-+++ src/Checks/Field.php
-@@ -86,7 +86,7 @@ class Field extends Check {
-         /** @var TypedDataInterface $property */
-         $value = $property->getValue();
-         if (is_string($value)) {
--          $field_name = $property->getDataDefinition()->getLabel();
-+          $field_name = $item->getFieldDefinition()->getLabel();
-           foreach ($tags as $vulnerability => $tag) {
-             if (strpos($value, '<' . $tag) !== FALSE) {
-               // Vulnerability found.
-@@ -138,9 +138,9 @@ class Field extends Check {
-           ->load($entity_id);
-         foreach ($fields as $field => $finding) {
--          $url = $entity->urlInfo('edit-form');
-+          $url = $entity->toUrl('edit-form')->toString();
-           if ($url === NULL) {
--            $url = $entity->urlInfo();
-+            $url = $entity->toUrl()->toString();
-           }
-           $items[] = $this->t(
-             '@vulnerabilities found in <em>@field</em> field of <a href=":url">@label</a>',
diff --git a/web/modules/contrib/security_review/src/Checks/FilePermissions.php b/web/modules/contrib/security_review/src/Checks/FilePermissions.php
deleted file mode 100644 (file)
index 17972b2..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\Core\StreamWrapper\PrivateStream;
-use Drupal\Core\StreamWrapper\PublicStream;
-use Drupal\Core\Url;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Check that files aren't writeable by the server.
- */
-class FilePermissions extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'File permissions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMachineTitle() {
-    return 'file_perms';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function storesFindings() {
-    return FALSE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run($cli = FALSE) {
-    $result = CheckResult::SUCCESS;
-
-    $file_list = $this->getFileList('.');
-    $writable = $this->security()->findWritableFiles($file_list, $cli);
-
-    // Try creating or appending files.
-    // Assume it doesn't work.
-    $create_status = FALSE;
-    $append_status = FALSE;
-
-    if (!$cli) {
-      $append_message = $this->t("Your web server should not be able to write to your modules directory. This is a security vulnerable. Consult the Security Review file permissions check help for mitigation steps.");
-      $directory = $this->moduleHandler()
-        ->getModule('security_review')
-        ->getPath();
-
-      // Write a file with the timestamp.
-      $file = './' . $directory . '/file_write_test.' . date('Ymdhis');
-      if ($file_create = @fopen($file, 'w')) {
-        $create_status = fwrite($file_create, date('Ymdhis') . ' - ' . $append_message . "\n");
-        fclose($file_create);
-      }
-
-      // Try to append to our IGNOREME file.
-      $file = './' . $directory . '/IGNOREME.txt';
-      if ($file_append = @fopen($file, 'a')) {
-        $append_status = fwrite($file_append, date('Ymdhis') . ' - ' . $append_message . "\n");
-        fclose($file_append);
-      }
-    }
-
-    if (!empty($writable) || $create_status || $append_status) {
-      $result = CheckResult::FAIL;
-    }
-
-    return $this->createResult($result, $writable);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function runCli() {
-    if (!$this->securityReview()->isServerPosix()) {
-      return $this->createResult(CheckResult::INFO);
-    }
-
-    return $this->run(TRUE);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('It is dangerous to allow the web server to write to files inside the document root of your server. Doing so could allow Drupal to write files that could then be executed. An attacker might use such a vulnerability to take control of your site. An exception is the Drupal files, private files, and temporary directories which Drupal needs permission to write to in order to provide features like file attachments.');
-    $paragraphs[] = $this->t('In addition to inspecting existing directories, this test attempts to create and write to your file system. Look in your security_review module directory on the server for files named file_write_test.YYYYMMDDHHMMSS and for a file called IGNOREME.txt which gets a timestamp appended to it if it is writeable.');
-    $paragraphs[] = new Link(
-      $this->t('Read more about file system permissions in the handbooks.'),
-      Url::fromUri('http://drupal.org/node/244924')
-    );
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Web server file system permissions'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    if ($result->result() == CheckResult::SUCCESS) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The following files and directories appear to be writeable by your web server. In most cases you can fix this by simply altering the file permissions or ownership. If you have command-line access to your host try running "chmod 644 [file path]" where [file path] is one of the following paths (relative to your webroot). For more information consult the <a href="http://drupal.org/node/244924">Drupal.org handbooks on file permissions</a>.');
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $result->findings(),
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    if ($result->result() == CheckResult::SUCCESS) {
-      return '';
-    }
-
-    $output = $this->t('Writable files:') . "\n";
-    foreach ($result->findings() as $file) {
-      $output .= "\t" . $file . "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Drupal installation files and directories (except required) are not writable by the server.');
-
-      case CheckResult::FAIL:
-        return $this->t('Some files and directories in your install are writable by the server.');
-
-      case CheckResult::INFO:
-        return $this->t('The test cannot be run on this system.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-  /**
-   * Scans a directory recursively and returns the files and directories inside.
-   *
-   * @param string $directory
-   *   The directory to scan.
-   * @param string[] $parsed
-   *   Array of already parsed real paths.
-   * @param string[] $ignore
-   *   Array of file names to ignore.
-   *
-   * @return string[]
-   *   The items found.
-   */
-  protected function getFileList($directory, array &$parsed = NULL, array &$ignore = NULL) {
-    // Initialize $parsed and $ignore arrays.
-    if ($parsed === NULL) {
-      $parsed = [realpath($directory)];
-    }
-    if ($ignore === NULL) {
-      $ignore = $this->getIgnoreList();
-    }
-
-    // Start scanning.
-    $items = [];
-    if ($handle = opendir($directory)) {
-      while (($file = readdir($handle)) !== FALSE) {
-        // Don't check hidden files or ones we said to ignore.
-        $path = $directory . "/" . $file;
-        if ($file[0] != "." && !in_array($file, $ignore) && !in_array(realpath($path), $ignore)) {
-          if (is_dir($path) && !in_array(realpath($path), $parsed)) {
-            $parsed[] = realpath($path);
-            $items = array_merge($items, $this->getFileList($path, $parsed, $ignore));
-          }
-          $items[] = preg_replace("/\/\//si", "/", $path);
-        }
-      }
-      closedir($handle);
-    }
-
-    return $items;
-  }
-
-  /**
-   * Returns an array of relative and canonical paths to ignore.
-   *
-   * @return string[]
-   *   List of relative and canonical file paths to ignore.
-   */
-  protected function getIgnoreList() {
-    $file_path = PublicStream::basePath();
-    $ignore = ['..', 'CVS', '.git', '.svn', '.bzr', realpath($file_path)];
-
-    // Add temporary files directory if it's set.
-    $temp_path = file_directory_temp();
-    if (!empty($temp_path)) {
-      $ignore[] = realpath('./' . rtrim($temp_path, '/'));
-    }
-
-    // Add private files directory if it's set.
-    $private_files = PrivateStream::basePath();
-    if (!empty($private_files)) {
-      // Remove leading slash if set.
-      if (strrpos($private_files, '/') !== FALSE) {
-        $private_files = substr($private_files, strrpos($private_files, '/') + 1);
-      }
-      $ignore[] = $private_files;
-    }
-
-    $this->moduleHandler()->alter('security_review_file_ignore', $ignore);
-    return $ignore;
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/InputFormats.php b/web/modules/contrib/security_review/src/Checks/InputFormats.php
deleted file mode 100644 (file)
index 4145540..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\Core\Url;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Checks for vulnerabilities related to input formats.
- *
- * Checks for formats that either do not have HTML filter that can be used by
- * untrusted users, or if they do check if unsafe tags are allowed.
- */
-class InputFormats extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Text formats';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMachineTitle() {
-    return 'input_formats';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    // If filter is not enabled return with INFO.
-    if (!$this->moduleHandler()->moduleExists('filter')) {
-      return $this->createResult(CheckResult::INFO);
-    }
-
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    $formats = filter_formats();
-    $untrusted_roles = $this->security()->untrustedRoles();
-    $unsafe_tags = $this->security()->unsafeTags();
-
-    foreach ($formats as $format) {
-      $format_roles = array_keys(filter_get_roles_by_format($format));
-      $intersect = array_intersect($format_roles, $untrusted_roles);
-
-      if (!empty($intersect)) {
-        // Untrusted users can use this format.
-        // Check format for enabled HTML filter.
-        $filter_html_enabled = FALSE;
-        if ($format->filters()->has('filter_html')) {
-          $filter_html_enabled = $format->filters('filter_html')
-            ->getConfiguration()['status'];
-        }
-        $filter_html_escape_enabled = FALSE;
-        if ($format->filters()->has('filter_html_escape')) {
-          $filter_html_escape_enabled = $format->filters('filter_html_escape')
-            ->getConfiguration()['status'];
-        }
-
-        if ($filter_html_enabled) {
-          $filter = $format->filters('filter_html');
-
-          // Check for unsafe tags in allowed tags.
-          $allowed_tags = array_keys($filter->getHTMLRestrictions()['allowed']);
-          foreach (array_intersect($allowed_tags, $unsafe_tags) as $tag) {
-            // Found an unsafe tag.
-            $findings['tags'][$format->id()] = $tag;
-          }
-        }
-        elseif (!$filter_html_escape_enabled) {
-          // Format is usable by untrusted users but does not contain the HTML
-          // Filter or the HTML escape.
-          $findings['formats'][$format->id()] = $format->label();
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-    }
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t("Certain HTML tags can allow an attacker to take control of your site. Drupal's input format system makes use of a set filters to run on incoming text. The 'HTML Filter' strips out harmful tags and Javascript events and should be used on all formats accessible by untrusted users.");
-    $paragraphs[] = new Link(
-      $this->t("Read more about Drupal's input formats in the handbooks."),
-      Url::fromUri('http://drupal.org/node/224921')
-    );
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Allowed HTML tags in text formats'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $output = [];
-
-    if (!empty($result->findings()['tags'])) {
-      $paragraphs = [];
-      $paragraphs[] = Link::createFromRoute(
-        $this->t('Review your text formats.'),
-        'filter.admin_overview'
-      );
-      $paragraphs[] = $this->t('It is recommended you remove the following tags from roles accessible by untrusted users.');
-      $output[] = [
-        '#theme' => 'check_evaluation',
-        '#paragraphs' => $paragraphs,
-        '#items' => $result->findings()['tags'],
-      ];
-    }
-
-    if (!empty($result->findings()['formats'])) {
-      $paragraphs = [];
-      $paragraphs[] = $this->t('The following formats are usable by untrusted roles and do not filter or escape allowed HTML tags.');
-      $output[] = [
-        '#theme' => 'check_evaluation',
-        '#paragraphs' => $paragraphs,
-        '#items' => $result->findings()['formats'],
-      ];
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $output = '';
-
-    if (!empty($result->findings()['tags'])) {
-      $output .= $this->t('Tags') . "\n";
-      foreach ($result->findings()['tags'] as $tag) {
-        $output .= "\t$tag\n";
-      }
-    }
-
-    if (!empty($result->findings()['formats'])) {
-      $output .= $this->t('Formats') . "\n";
-      foreach ($result->findings()['formats'] as $format) {
-        $output .= "\t$format\n";
-      }
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Untrusted users are not allowed to input dangerous HTML tags.');
-
-      case CheckResult::FAIL:
-        return $this->t('Untrusted users are allowed to input dangerous HTML tags.');
-
-      case CheckResult::INFO:
-        return $this->t('Module filter is not enabled.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/PrivateFiles.php b/web/modules/contrib/security_review/src/Checks/PrivateFiles.php
deleted file mode 100644 (file)
index e40649e..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\Core\StreamWrapper\PrivateStream;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Checks whether the private files' directory is under the web root.
- */
-class PrivateFiles extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Private files';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    $file_directory_path = PrivateStream::basePath();
-    $visible = TRUE;
-    if (empty($file_directory_path)) {
-      // Private files feature is not enabled.
-      $result = CheckResult::SUCCESS;
-      $visible = FALSE;
-    }
-    elseif (strpos(realpath($file_directory_path), DRUPAL_ROOT) === 0) {
-      // Path begins at root.
-      $result = CheckResult::FAIL;
-    }
-    else {
-      // The private files directory is placed correctly.
-      $result = CheckResult::SUCCESS;
-    }
-    return $this->createResult($result, ['path' => $file_directory_path], $visible);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t("If you have Drupal's private files feature enabled you should move the files directory outside of the web server's document root. Drupal will secure access to files that it renders the link to, but if a user knows the actual system path they can circumvent Drupal's private files feature. You can protect against this by specifying a files directory outside of the webserver root.");
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Private files'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    if ($result->result() != CheckResult::FAIL) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('Your files directory is not outside of the server root.');
-    $paragraphs[] = Link::createFromRoute(
-      $this->t('Edit the files directory path.'),
-      'system.file_system_settings'
-    );
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => [],
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    if ($result->result() != CheckResult::FAIL) {
-      return '';
-    }
-
-    return $this->t('Private files directory: @path', ['@path' => $result->findings()['path']]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Private files directory is outside the web server root.');
-
-      case CheckResult::FAIL:
-        return $this->t('Private files is enabled but the specified directory is not secure outside the web server root.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/QueryErrors.php b/web/modules/contrib/security_review/src/Checks/QueryErrors.php
deleted file mode 100644 (file)
index ed61010..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Checks for abundant query errors.
- */
-class QueryErrors extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Query errors';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    // If dblog is not enabled return with hidden INFO.
-    if (!$this->moduleHandler()->moduleExists('dblog')) {
-      return $this->createResult(CheckResult::INFO, [], FALSE);
-    }
-
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-    $last_result = $this->lastResult();
-    $visible = FALSE;
-
-    // Prepare the query.
-    $query = $this->database()->select('watchdog', 'w');
-    $query->fields('w', [
-      'severity',
-      'type',
-      'timestamp',
-      'message',
-      'variables',
-      'hostname',
-    ]);
-    $query->condition('type', 'php')->condition('severity', RfcLogLevel::ERROR);
-    if ($last_result instanceof CheckResult) {
-      // Only check entries that got recorded since the last run of the check.
-      $query->condition('timestamp', $last_result->time(), '>=');
-    }
-
-    // Execute the query.
-    $db_result = $query->execute();
-
-    // Count the number of query errors per IP.
-    $entries = [];
-    foreach ($db_result as $row) {
-      // Get the message.
-      if ($row->variables === 'N;') {
-        $message = $row->message;
-      }
-      else {
-        $message = $this->t($row->message, unserialize($row->variables));
-      }
-
-      // Get the IP.
-      $ip = $row->hostname;
-
-      // Search for query errors.
-      $message_contains_sql = strpos($message, 'SQL') !== FALSE;
-      $message_contains_select = strpos($message, 'SELECT') !== FALSE;
-      if ($message_contains_sql && $message_contains_select) {
-        $entry_for_ip = &$entries[$ip];
-
-        if (!isset($entry_for_ip)) {
-          $entry_for_ip = 0;
-        }
-        $entry_for_ip++;
-      }
-    }
-
-    // Filter the IPs with more than 10 query errors.
-    if (!empty($entries)) {
-      foreach ($entries as $ip => $count) {
-        if ($count > 10) {
-          $findings[] = $ip;
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-      $visible = TRUE;
-    }
-
-    return $this->createResult($result, $findings, $visible);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('Database errors triggered from the same IP may be an artifact of a malicious user attempting to probe the system for weaknesses like SQL injection or information disclosure.');
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Abundant query errors from the same IP'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The following IPs were observed with an abundance of query errors.');
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $result->findings(),
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return '';
-    }
-
-    $output = $this->t('Suspicious IP addresses:') . ":\n";
-    foreach ($findings as $ip) {
-      $output .= "\t" . $ip . "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::FAIL:
-        return $this->t('Query errors from the same IP. These may be a SQL injection attack or an attempt at information disclosure.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/TemporaryFiles.php b/web/modules/contrib/security_review/src/Checks/TemporaryFiles.php
deleted file mode 100644 (file)
index cbdb065..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * Check for sensitive temporary files like settings.php~.
- */
-class TemporaryFiles extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Temporary files';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    // Get list of files from the site directory.
-    $files = [];
-    $site_path = $this->security()->sitePath() . '/';
-    $dir = scandir($site_path);
-    foreach ($dir as $file) {
-      // Set full path to only files.
-      if (!is_dir($file)) {
-        $files[] = $site_path . $file;
-      }
-    }
-    $this->moduleHandler()->alter('security_review_temporary_files', $files);
-
-    // Analyze the files' names.
-    foreach ($files as $path) {
-      $matches = [];
-      if (file_exists($path) && preg_match('/.*(~|\.sw[op]|\.bak|\.orig|\.save)$/', $path, $matches) !== FALSE && !empty($matches)) {
-        // Found a temporary file.
-        $findings[] = $path;
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t("Some file editors create temporary copies of a file that can be left on the file system. A copy of a sensitive file like Drupal's settings.php may be readable by a malicious user who could use that information to further attack a site.");
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Sensitive temporary files'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t("The following are extraneous files in your Drupal installation that can probably be removed. You should confirm you have saved any of your work in the original files prior to removing these.");
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $findings,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return '';
-    }
-
-    $output = $this->t('Temporary files:') . "\n";
-    foreach ($findings as $file) {
-      $output .= "\t" . $file . "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('No sensitive temporary files were found.');
-
-      case CheckResult::FAIL:
-        return $this->t('Sensitive temporary files were found on your files system.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/TrustedHosts.php b/web/modules/contrib/security_review/src/Checks/TrustedHosts.php
deleted file mode 100644 (file)
index 947f32d..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\Core\Url;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-use Drupal\security_review\CheckSettings\TrustedHostSettings;
-
-/**
- * Checks for base_url and trusted_host_patterns settings in settings.php.
- */
-class TrustedHosts extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct() {
-    parent::__construct();
-    $this->settings = new TrustedHostSettings($this, $this->config);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Trusted hosts';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    $result = CheckResult::FAIL;
-    $base_url_set = FALSE;
-    $trusted_host_patterns_set = FALSE;
-    $findings = [];
-    $settings_php = $this->security()->sitePath() . '/settings.php';
-
-    if (!file_exists($settings_php)) {
-      return $this->createResult(CheckResult::INFO, [], FALSE);
-    }
-
-    if ($this->settings()->get('method', 'token') === 'token') {
-      // Use tokenization.
-      $content = file_get_contents($settings_php);
-      $tokens = token_get_all($content);
-
-      $prev_settings_line = -1;
-      foreach ($tokens as $token) {
-        if (is_array($token)) {
-          // Get information about the current token.
-          $line = $token[2];
-          $is_variable = $token[0] === T_VARIABLE;
-          $is_string = $token[0] === T_CONSTANT_ENCAPSED_STRING;
-          $is_settings = $is_variable ? $token[1] == '$settings' : FALSE;
-          $is_base_url = $token[1] == '$base_url';
-          $is_thp = trim($token[1], "\"'") == 'trusted_host_patterns';
-          $is_after_settings = $line == $prev_settings_line;
-
-          // Check for $base_url.
-          if ($is_variable && $is_base_url) {
-            $base_url_set = TRUE;
-            $result = CheckResult::SUCCESS;
-          }
-
-          // Check for $settings['trusted_host_patterns'].
-          if ($is_after_settings && $is_string && $is_thp) {
-            $trusted_host_patterns_set = TRUE;
-            $result = CheckResult::SUCCESS;
-          }
-
-          // If found both settings stop the review.
-          if ($base_url_set && $trusted_host_patterns_set) {
-            // Got everything we need.
-            break;
-          }
-
-          // Store last $settings line.
-          if ($is_settings) {
-            $prev_settings_line = $line;
-          }
-        }
-      }
-    }
-    else {
-      // Use inclusion.
-      include $settings_php;
-      $base_url_set = isset($base_url);
-      $trusted_host_patterns_set = isset($settings['trusted_host_patterns']);
-    }
-
-    if ($result === CheckResult::FAIL) {
-      // Provide information if the check failed.
-      global $base_url;
-      $findings['base_url'] = $base_url;
-      $findings['settings'] = $settings_php;
-      $findings['base_url_set'] = $base_url_set;
-      $findings['trusted_host_patterns_set'] = $trusted_host_patterns_set;
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t('Often Drupal needs to know the URL(s) it is responding from in order to build full links back to itself (e.g. password reset links sent via email). Until you explicitly tell Drupal what full or partial URL(s) it should respond for it must dynamically detect it based on the incoming request, something that can be malicously spoofed in order to trick someone into unknowningly visiting an attacker\'s site (known as a HTTP host header attack).');
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Drupal trusted hosts'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    global $base_url;
-    if ($result->result() !== CheckResult::FAIL) {
-      return [];
-    }
-
-    $settings_php = $this->security()->sitePath() . '/settings.php';
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('This site is responding from the URL: :url.', [':url' => $base_url]);
-    $paragraphs[] = $this->t('If the site should be available only at that URL it is recommended that you set it as the $base_url variable in the settings.php file at @file.', ['@file' => $settings_php]);
-    $paragraphs[] = $this->t('If the site has multiple URLs it can respond from you should whitelist host patterns with trusted_host_patterns in settings.php.');
-    $paragraphs[] = new Link($this->t('Read more about HTTP Host Header attacks and setting trusted_host_patterns.'), Url::fromUri('https://www.drupal.org/node/1992030'));
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => [],
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Either $base_url or trusted_host_patterns is set.');
-
-      case CheckResult::FAIL:
-        return $this->t('Neither $base_url nor trusted_host_patterns is set.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/UploadExtensions.php b/web/modules/contrib/security_review/src/Checks/UploadExtensions.php
deleted file mode 100644 (file)
index 8cfe5ad..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\Core\Url;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-use Symfony\Component\Routing\Exception\RouteNotFoundException;
-
-/**
- * Checks for unsafe extensions in the allowed extensions settings of fields.
- */
-class UploadExtensions extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Allowed upload extensions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMachineTitle() {
-    return 'upload_extensions';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    // If field is not enabled return with INFO.
-    if (!$this->moduleHandler()->moduleExists('field')) {
-      return $this->createResult(CheckResult::INFO);
-    }
-
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    // Check field configuration entities.
-    foreach (FieldConfig::loadMultiple() as $entity) {
-      /** @var FieldConfig $entity */
-      $extensions = $entity->getSetting('file_extensions');
-      if ($extensions != NULL) {
-        $extensions = explode(' ', $extensions);
-        $intersect = array_intersect($extensions, $this->security()->unsafeExtensions());
-        // $intersect holds the unsafe extensions this entity allows.
-        foreach ($intersect as $unsafe_extension) {
-          $findings[$entity->id()][] = $unsafe_extension;
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t(
-      'File and image fields allow for uploaded files. Some extensions are considered dangerous because the files can be evaluated and then executed in the browser. A malicious user could use this opening to gain control of your site. Review <a href=":url">all fields on your site</a>.',
-      [':url' => Url::fromRoute('entity.field_storage_config.collection')->toString()]
-    );
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => 'Allowed upload extensions',
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The following extensions are considered unsafe and should be removed or limited from use. Or, be sure you are not granting untrusted users the ability to upload files.');
-
-    $items = [];
-    foreach ($findings as $entity_id => $unsafe_extensions) {
-      $entity = FieldConfig::load($entity_id);
-      /** @var FieldConfig $entity */
-
-      foreach ($unsafe_extensions as $extension) {
-        $item = $this->t(
-          'Review @type in <em>@field</em> field on @bundle',
-          [
-            '@type' => $extension,
-            '@field' => $entity->label(),
-            '@bundle' => $entity->getTargetBundle(),
-          ]
-        );
-
-        // Try to get an edit url.
-        try {
-          $url_params = ['field_config' => $entity->id()];
-          if ($entity->getTargetEntityTypeId() == 'node') {
-            $url_params['node_type'] = $entity->getTargetBundle();
-          }
-          $items[] = Link::createFromRoute(
-            $item,
-            sprintf('entity.field_config.%s_field_edit_form', $entity->getTargetEntityTypeId()),
-            $url_params
-          );
-        }
-        catch (RouteNotFoundException $e) {
-          $items[] = $item;
-        }
-      }
-    }
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $items,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return '';
-    }
-
-    $output = '';
-    foreach ($findings as $entity_id => $unsafe_extensions) {
-      $entity = FieldConfig::load($entity_id);
-      /** @var FieldConfig $entity */
-
-      $output .= $this->t(
-        '@bundle: field @field',
-        [
-          '@bundle' => $entity->getTargetBundle(),
-          '@field' => $entity->label(),
-        ]
-      );
-      $output .= "\n\t" . implode(', ', $unsafe_extensions) . "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Only safe extensions are allowed for uploaded files and images.');
-
-      case CheckResult::FAIL:
-        return $this->t('Unsafe file extensions are allowed in uploads.');
-
-      case CheckResult::INFO:
-        return $this->t('Module field is not enabled.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Checks/ViewsAccess.php b/web/modules/contrib/security_review/src/Checks/ViewsAccess.php
deleted file mode 100644 (file)
index 5a28b19..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Checks;
-
-use Drupal\Core\Link;
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-use Drupal\views\Entity\View;
-
-/**
- * Checks for Views that do not check access.
- */
-class ViewsAccess extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Views access';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    // If views is not enabled return with INFO.
-    if (!$this->moduleHandler()->moduleExists('views')) {
-      return $this->createResult(CheckResult::INFO);
-    }
-
-    $result = CheckResult::SUCCESS;
-    $findings = [];
-
-    $views = View::loadMultiple();
-    /** @var View[] $views */
-
-    // Iterate through views and their displays.
-    foreach ($views as $view) {
-      if ($view->status()) {
-        foreach ($view->get('display') as $display_name => $display) {
-          $access = &$display['display_options']['access'];
-          if (isset($access) && $access['type'] == 'none') {
-            // Access is not controlled for this display.
-            $findings[$view->id()][] = $display_name;
-          }
-        }
-      }
-    }
-
-    if (!empty($findings)) {
-      $result = CheckResult::FAIL;
-    }
-
-    return $this->createResult($result, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    $paragraphs = [];
-    $paragraphs[] = $this->t("Views can check if the user is allowed access to the content. It is recommended that all Views implement some amount of access control, at a minimum checking for the permission 'access content'.");
-
-    return [
-      '#theme' => 'check_help',
-      '#title' => $this->t('Views access'),
-      '#paragraphs' => $paragraphs,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluate(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return [];
-    }
-
-    $paragraphs = [];
-    $paragraphs[] = $this->t('The following View displays do not check access.');
-
-    $items = [];
-    foreach ($findings as $view_id => $displays) {
-      $view = View::load($view_id);
-      /** @var View $view */
-
-      foreach ($displays as $display) {
-        $items[] = Link::createFromRoute(
-          $view->label() . ': ' . $display,
-          'entity.view.edit_display_form',
-          [
-            'view' => $view_id,
-            'display_id' => $display,
-          ]
-        );
-      }
-    }
-
-    return [
-      '#theme' => 'check_evaluation',
-      '#paragraphs' => $paragraphs,
-      '#items' => $items,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function evaluatePlain(CheckResult $result) {
-    $findings = $result->findings();
-    if (empty($findings)) {
-      return '';
-    }
-
-    $output = $this->t('Views without access check:') . ":\n";
-    foreach ($findings as $view_id => $displays) {
-      $output .= "\t" . $view_id . ": " . implode(', ', $displays) . "\n";
-    }
-
-    return $output;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    switch ($result_const) {
-      case CheckResult::SUCCESS:
-        return $this->t('Views are access controlled.');
-
-      case CheckResult::FAIL:
-        return $this->t('There are Views that do not provide any access checks.');
-
-      case CheckResult::INFO:
-        return $this->t('Module views is not enabled.');
-
-      default:
-        return $this->t('Unexpected result.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Controller/ChecklistController.php b/web/modules/contrib/security_review/src/Controller/ChecklistController.php
deleted file mode 100644 (file)
index 1ce78b6..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Controller;
-
-use Drupal\Core\Access\CsrfTokenGenerator;
-use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\Link;
-use Drupal\Core\Url;
-use Drupal\security_review\Checklist;
-use Drupal\security_review\SecurityReview;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * The class of the 'Run & Review' page's controller.
- */
-class ChecklistController extends ControllerBase {
-
-  /**
-   * The CSRF Token generator.
-   *
-   * @var \Drupal\Core\Access\CsrfTokenGenerator $csrfToken
-   */
-  protected $csrfToken;
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * The security_review service.
-   *
-   * @var \Drupal\security_review\SecurityReview
-   */
-  protected $securityReview;
-
-
-  /**
-   * Constructs a ChecklistController.
-   *
-   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token_generator
-   *   The CSRF Token generator.
-   * @param \Drupal\security_review\SecurityReview $security_review
-   *   The security_review service.
-   * @param \Drupal\security_review\Checklist $checklist
-   *   The security_review.checklist service.
-   */
-  public function __construct(CsrfTokenGenerator $csrf_token_generator, SecurityReview $security_review, Checklist $checklist) {
-    $this->csrfToken = $csrf_token_generator;
-    $this->checklist = $checklist;
-    $this->securityReview = $security_review;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('csrf_token'),
-      $container->get('security_review'),
-      $container->get('security_review.checklist')
-    );
-  }
-
-  /**
-   * Creates the Run & Review page.
-   *
-   * @return array
-   *   The 'Run & Review' page's render array.
-   */
-  public function index() {
-    $run_form = [];
-
-    // If the user has the required permissions, show the RunForm.
-    if ($this->currentUser()->hasPermission('run security checks')) {
-      // Get the Run form.
-      $run_form = $this->formBuilder()
-        ->getForm('Drupal\security_review\Form\RunForm');
-
-      // Close the Run form if there are results.
-      if ($this->securityReview->getLastRun() > 0) {
-        $run_form['run_form']['#open'] = FALSE;
-      }
-    }
-
-    // Print the results if any.
-    if ($this->securityReview->getLastRun() <= 0) {
-      // If they haven't configured the site, prompt them to do so.
-      if (!$this->securityReview->isConfigured()) {
-        drupal_set_message($this->t('It appears this is your first time using the Security Review checklist. Before running the checklist please review the settings page at <a href=":url">admin/reports/security-review/settings</a> to set which roles are untrusted.',
-          [':url' => Url::fromRoute('security_review.settings')->toString()]
-        ), 'warning');
-      }
-    }
-
-    return [$run_form, $this->results()];
-  }
-
-  /**
-   * Creates the results' table.
-   *
-   * @return array
-   *   The render array for the result table.
-   */
-  public function results() {
-    // If there are no results return.
-    if ($this->securityReview->getLastRun() <= 0) {
-      return [];
-    }
-
-    $checks = [];
-    foreach ($this->checklist->getChecks() as $check) {
-      // Initialize with defaults.
-      $check_info = [
-        'message' => $this->t(
-          'The check "@name" hasn\'t been run yet.',
-          ['@name' => $check->getTitle()]
-        ),
-        'skipped' => $check->isSkipped(),
-      ];
-
-      // Get last result.
-      $last_result = $check->lastResult();
-      if ($last_result != NULL) {
-        if (!$last_result->isVisible()) {
-          continue;
-        }
-        $check_info['result'] = $last_result->result();
-        $check_info['message'] = $last_result->resultMessage();
-      }
-
-      // Determine help link.
-      $check_info['help_link'] = Link::createFromRoute(
-        'Details',
-        'security_review.help',
-        [
-          'namespace' => $check->getMachineNamespace(),
-          'title' => $check->getMachineTitle(),
-        ]
-      );
-
-      // Add toggle button.
-      $toggle_text = $check->isSkipped() ? 'Enable' : 'Skip';
-      $check_info['toggle_link'] = Link::createFromRoute($toggle_text,
-        'security_review.toggle',
-        ['check_id' => $check->id()],
-        ['query' => ['token' => $this->csrfToken->get($check->id())]]
-      );
-
-      // Add to array of completed checks.
-      $checks[] = $check_info;
-    }
-
-    return [
-      '#theme' => 'run_and_review',
-      '#date' => $this->securityReview->getLastRun(),
-      '#checks' => $checks,
-      '#attached' => [
-        'library' => ['security_review/run_and_review'],
-      ],
-    ];
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Controller/HelpController.php b/web/modules/contrib/security_review/src/Controller/HelpController.php
deleted file mode 100644 (file)
index 048be73..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Controller;
-
-use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\Datetime\DateFormatterInterface;
-use Drupal\Core\Link;
-use Drupal\security_review\Checklist;
-use Drupal\security_review\CheckResult;
-use Drupal\security_review\SecurityReview;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-
-/**
- * The class of the Help pages' controller.
- */
-class HelpController extends ControllerBase {
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * The security_review service.
-   *
-   * @var \Drupal\security_review\SecurityReview
-   */
-  protected $securityReview;
-
-  /**
-   * The date.formatter service.
-   *
-   * @var \Drupal\Core\Datetime\DateFormatterInterface
-   */
-  private $dateFormatter;
-
-  /**
-   * Constructs a HelpController.
-   *
-   * @param \Drupal\security_review\SecurityReview $security_review
-   *   The security_review service.
-   * @param \Drupal\security_review\Checklist $checklist
-   *   The security_review.checklist service.
-   * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
-   *   The date.formatter service.
-   */
-  public function __construct(SecurityReview $security_review, Checklist $checklist, DateFormatterInterface $dateFormatter) {
-    // Store the dependencies.
-    $this->checklist = $checklist;
-    $this->securityReview = $security_review;
-    $this->dateFormatter = $dateFormatter;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('security_review'),
-      $container->get('security_review.checklist'),
-      $container->get('date.formatter')
-    );
-  }
-
-  /**
-   * Serves as an entry point for the help pages.
-   *
-   * @param string|NULL $namespace
-   *   The namespace of the check (null if general page).
-   * @param string $title
-   *   The name of the check.
-   *
-   * @return array
-   *   The requested help page.
-   */
-  public function index($namespace, $title) {
-    // If no namespace is set, print the general help page.
-    if ($namespace === NULL) {
-      return $this->generalHelp();
-    }
-
-    // Print check-specific help.
-    return $this->checkHelp($namespace, $title);
-  }
-
-  /**
-   * Returns the general help page.
-   *
-   * @return array
-   *   The general help page.
-   */
-  private function generalHelp() {
-    $paragraphs = [];
-
-    // Print the general help.
-    $paragraphs[] = $this->t('You should take the security of your site very seriously. Fortunately, Drupal is fairly secure by default. The Security Review module automates many of the easy-to-make mistakes that render your site insecure, however it does not automatically make your site impenetrable. You should give care to what modules you install and how you configure your site and server. Be mindful of who visits your site and what features you expose for their use.');
-    $paragraphs[] = $this->t('You can read more about securing your site in the <a href="http://drupal.org/security/secure-configuration">drupal.org handbooks</a> and on <a href="http://crackingdrupal.com">CrackingDrupal.com</a>. There are also additional modules you can install to secure or protect your site. Be aware though that the more modules you have running on your site the greater (usually) attack area you expose.');
-    $paragraphs[] = $this->t('<a href="http://drupal.org/node/382752">Drupal.org Handbook: Introduction to security-related contrib modules</a>');
-
-    // Print the list of security checks with links to their help pages.
-    $checks = [];
-    foreach ($this->checklist->getChecks() as $check) {
-      // Get the namespace array's reference.
-      $check_namespace = &$checks[$check->getMachineNamespace()];
-
-      // Set up the namespace array if not set.
-      if (!isset($check_namespace)) {
-        $check_namespace['namespace'] = $check->getNamespace();
-        $check_namespace['check_links'] = [];
-      }
-
-      // Add the link pointing to the check-specific help.
-      $check_namespace['check_links'][] = Link::createFromRoute(
-        $this->t('@title', ['@title' => $check->getTitle()]),
-        'security_review.help',
-        [
-          'namespace' => $check->getMachineNamespace(),
-          'title' => $check->getMachineTitle(),
-        ]
-      );
-    }
-
-    return [
-      '#theme' => 'general_help',
-      '#paragraphs' => $paragraphs,
-      '#checks' => $checks,
-    ];
-  }
-
-  /**
-   * Returns a check-specific help page.
-   *
-   * @param string $namespace
-   *   The namespace of the check.
-   * @param string $title
-   *   The name of the check.
-   *
-   * @return array
-   *   The check's help page.
-   *
-   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
-   *   If the check is not found.
-   */
-  private function checkHelp($namespace, $title) {
-    // Get the requested check.
-    $check = $this->checklist->getCheck($namespace, $title);
-
-    // If the check doesn't exist, throw 404.
-    if ($check == NULL) {
-      throw new NotFoundHttpException();
-    }
-
-    // Print the help page.
-    $output = [];
-    $output[] = $check->help();
-
-    // If the check is skipped print the skip message, else print the
-    // evaluation.
-    if ($check->isSkipped()) {
-
-      if ($check->skippedBy() != NULL) {
-        $user = $check->skippedBy()->link();
-      }
-      else {
-        $user = 'Anonymous';
-      }
-
-      $skip_message = $this->t(
-        'Check marked for skipping on @date by @user',
-        [
-          '@date' => $this->dateFormatter->format($check->skippedOn()),
-          '@user' => $user,
-        ]
-      );
-
-      $output[] = [
-        '#type' => 'markup',
-        '#markup' => "<p>$skip_message</p>",
-      ];
-    }
-    else {
-      // Evaluate last result, if any.
-      $last_result = $check->lastResult(TRUE);
-      if ($last_result instanceof CheckResult) {
-        // Separator.
-        $output[] = [
-          '#type' => 'markup',
-          '#markup' => '<div />',
-        ];
-
-        // Evaluation page.
-        $output[] = $check->evaluate($last_result);
-      }
-    }
-
-    // Return the completed page.
-    return $output;
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Controller/ToggleController.php b/web/modules/contrib/security_review/src/Controller/ToggleController.php
deleted file mode 100644 (file)
index 4fd9cfe..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Controller;
-
-use Drupal\Core\Access\CsrfTokenGenerator;
-use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\Url;
-use Drupal\security_review\Checklist;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\RequestStack;
-
-/**
- * Responsible for handling the toggle links on the Run & Review page.
- */
-class ToggleController extends ControllerBase {
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * The CSRF Token generator.
-   *
-   * @var \Drupal\Core\Access\CsrfTokenGenerator $csrfToken
-   */
-  protected $csrfToken;
-
-  /**
-   * The request stack.
-   *
-   * @var \Symfony\Component\HttpFoundation\Request $request
-   */
-  protected $request;
-
-  /**
-   * Constructs a ToggleController.
-   *
-   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token_generator
-   *   The CSRF Token generator.
-   * @param \Symfony\Component\HttpFoundation\RequestStack $request
-   *   The request stack.
-   * @param \Drupal\security_review\Checklist $checklist
-   *   The security_review.checklist service.
-   */
-  public function __construct(CsrfTokenGenerator $csrf_token_generator, RequestStack $request, Checklist $checklist) {
-    $this->checklist = $checklist;
-    $this->csrfToken = $csrf_token_generator;
-    $this->request = $request->getCurrentRequest();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('csrf_token'),
-      $container->get('request_stack'),
-      $container->get('security_review.checklist')
-    );
-  }
-
-  /**
-   * Handles check toggling.
-   *
-   * @param string $check_id
-   *   The ID of the check.
-   *
-   * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
-   *   The response.
-   */
-  public function index($check_id) {
-    // Determine access type.
-    $ajax = $this->request->query->get('js') == 1;
-
-    // Validate token.
-    $token = $this->request->query->get('token');
-    if ($this->csrfToken->validate($token, $check_id)) {
-      // Toggle.
-      $check = $this->checklist->getCheckById($check_id);
-      if ($check != NULL) {
-        if ($check->isSkipped()) {
-          $check->enable();
-        }
-        else {
-          $check->skip();
-        }
-      }
-
-      // Output.
-      if ($ajax) {
-        return new JsonResponse([
-          'skipped' => $check->isSkipped(),
-          'toggle_text' => $check->isSkipped() ? $this->t('Enable') : $this->t('Skip'),
-          'toggle_href' => Url::fromRoute(
-            'security_review.toggle',
-            ['check_id' => $check->id()],
-            [
-              'query' => [
-                'token' => $this->csrfToken->get($check->id()),
-                'js' => 1,
-              ],
-            ]
-          )->toString(),
-        ]);
-      }
-      else {
-        // Set message.
-        if ($check->isSkipped()) {
-          drupal_set_message($this->t(
-            '@name check skipped.',
-            ['@name' => $check->getTitle()]
-          ));
-        }
-        else {
-          drupal_set_message($this->t(
-            '@name check no longer skipped.',
-            ['@name' => $check->getTitle()]
-          ));
-        }
-
-        // Redirect back to Run & Review.
-        return $this->redirect('security_review');
-      }
-    }
-
-    // Go back to Run & Review if the access was wrong.
-    return $this->redirect('security_review');
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Form/RunForm.php b/web/modules/contrib/security_review/src/Form/RunForm.php
deleted file mode 100644 (file)
index 16b50ba..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Form;
-
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\security_review\Checklist;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides implementation for the Run form.
- */
-class RunForm extends FormBase {
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * Constructs a RunForm.
-   *
-   * @param \Drupal\security_review\Checklist $checklist
-   *   The security_review.checklist service.
-   */
-  public function __construct(Checklist $checklist) {
-    $this->checklist = $checklist;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('security_review.checklist')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'security-review-run';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state) {
-    if (!$this->currentUser()->hasPermission('run security checks')) {
-      return [];
-    }
-
-    $form['run_form'] = [
-      '#type' => 'details',
-      '#title' => $this->t('Run'),
-      '#description' => $this->t('Click the button below to run the security checklist and review the results.') . '<br />',
-      '#open' => TRUE,
-    ];
-
-    $form['run_form']['submit'] = [
-      '#type' => 'submit',
-      '#value' => $this->t('Run checklist'),
-    ];
-
-    // Return the finished form.
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $batch = [
-      'operations' => [],
-      'finished' => '_security_review_batch_run_finished',
-      'title' => $this->t('Performing Security Review'),
-      'init_message' => $this->t('Security Review is starting.'),
-      'progress_message' => $this->t('Progress @current out of @total.'),
-      'error_message' => $this->t('An error occurred. Rerun the process or consult the logs.'),
-    ];
-
-    foreach ($this->checklist->getEnabledChecks() as $check) {
-      $batch['operations'][] = [
-        '_security_review_batch_run_op',
-        [$check],
-      ];
-    }
-
-    batch_set($batch);
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Form/SettingsForm.php b/web/modules/contrib/security_review/src/Form/SettingsForm.php
deleted file mode 100644 (file)
index 5ba0757..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Form;
-
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Datetime\DateFormatterInterface;
-use Drupal\Core\Form\ConfigFormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\security_review\Checklist;
-use Drupal\security_review\Security;
-use Drupal\security_review\SecurityReview;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Settings page for Security Review.
- */
-class SettingsForm extends ConfigFormBase {
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * The security_review.security service.
-   *
-   * @var \Drupal\security_review\Security
-   */
-  protected $security;
-
-  /**
-   * The security_review service.
-   *
-   * @var \Drupal\security_review\SecurityReview
-   */
-  protected $securityReview;
-
-  /**
-   * The date.formatter service.
-   *
-   * @var \Drupal\Core\Datetime\DateFormatterInterface
-   */
-  private $dateFormatter;
-
-  /**
-   * Constructs a SettingsForm.
-   *
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory.
-   * @param \Drupal\security_review\Checklist $checklist
-   *   The security_review.checklist service.
-   * @param \Drupal\security_review\Security $security
-   *   The security_review.security service.
-   * @param \Drupal\security_review\SecurityReview $security_review
-   *   The security_review service.
-   * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
-   *   The date.formatter service.
-   */
-  public function __construct(ConfigFactoryInterface $config_factory, Checklist $checklist, Security $security, SecurityReview $security_review, DateFormatterInterface $dateFormatter) {
-    parent::__construct($config_factory);
-    $this->checklist = $checklist;
-    $this->security = $security;
-    $this->securityReview = $security_review;
-    $this->dateFormatter = $dateFormatter;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('config.factory'),
-      $container->get('security_review.checklist'),
-      $container->get('security_review.security'),
-      $container->get('security_review'),
-      $container->get('date.formatter')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'security-review-settings';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state) {
-    // Get the list of checks.
-    $checks = $this->checklist->getChecks();
-
-    // Get the user roles.
-    $roles = user_roles();
-    $options = [];
-    foreach ($roles as $rid => $role) {
-      $options[$rid] = $role->label();
-    }
-
-    // Notify the user if anonymous users can create accounts.
-    $message = '';
-    if (in_array(AccountInterface::AUTHENTICATED_ROLE, $this->security->defaultUntrustedRoles())) {
-      $message = $this->t('You have allowed anonymous users to create accounts without approval so the authenticated role defaults to untrusted.');
-    }
-
-    // Show the untrusted roles form element.
-    $form['untrusted_roles'] = [
-      '#type' => 'checkboxes',
-      '#title' => $this->t('Untrusted roles'),
-      '#description' => $this->t(
-        'Define which roles are for less trusted users. The anonymous role defaults to untrusted. @message Most Security Review checks look for resources usable by untrusted roles.',
-        ['@message' => $message]
-      ),
-      '#options' => $options,
-      '#default_value' => $this->security->untrustedRoles(),
-    ];
-
-    $form['advanced'] = [
-      '#type' => 'details',
-      '#title' => $this->t('Advanced'),
-      '#open' => TRUE,
-    ];
-
-    // Show the logging setting.
-    $form['advanced']['logging'] = [
-      '#type' => 'checkbox',
-      '#title' => $this->t('Log checklist results and skips'),
-      '#description' => $this->t('The result of each check and skip can be logged to watchdog for tracking.'),
-      '#default_value' => $this->securityReview->isLogging(),
-    ];
-
-    // Skipped checks.
-    $values = [];
-    $options = [];
-    foreach ($checks as $check) {
-      // Determine if check is being skipped.
-      if ($check->isSkipped()) {
-        $values[] = $check->id();
-        $label = $this->t(
-          '@name <em>skipped by UID @uid on @date</em>',
-          [
-            '@name' => $check->getTitle(),
-            '@uid' => $check->skippedBy()->id(),
-            '@date' => $this->dateFormatter->format($check->skippedOn()),
-          ]
-        );
-      }
-      else {
-        $label = $check->getTitle();
-      }
-      $options[$check->id()] = $label;
-    }
-    $form['advanced']['skip'] = [
-      '#type' => 'checkboxes',
-      '#title' => $this->t('Checks to skip'),
-      '#description' => $this->t('Skip running certain checks. This can also be set on the <em>Run & review</em> page. It is recommended that you do not skip any checks unless you know the result is wrong or the process times out while running.'),
-      '#options' => $options,
-      '#default_value' => $values,
-    ];
-
-    // Iterate through checklist and get check-specific setting pages.
-    foreach ($checks as $check) {
-      // Get the check's setting form.
-      $check_form = $check->settings()->buildForm();
-
-      // If not empty, add it to the form.
-      if (!empty($check_form)) {
-        // If this is the first non-empty setting page initialize the 'details'
-        if (!isset($form['advanced']['check_specific'])) {
-          $form['advanced']['check_specific'] = [
-            '#type' => 'details',
-            '#title' => $this->t('Check-specific settings'),
-            '#open' => FALSE,
-            '#tree' => TRUE,
-          ];
-        }
-
-        // Add the form.
-        $sub_form = &$form['advanced']['check_specific'][$check->id()];
-
-        $title = $check->getTitle();
-        // If it's an external check, show its namespace.
-        if ($check->getMachineNamespace() != 'security_review') {
-          $title .= $this->t('%namespace', [
-            '%namespace' => $check->getNamespace(),
-          ]);
-        }
-        $sub_form = [
-          '#type' => 'details',
-          '#title' => $title,
-          '#open' => TRUE,
-          '#tree' => TRUE,
-          'form' => $check_form,
-        ];
-      }
-    }
-
-    // Return the finished form.
-    return parent::buildForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    // Run validation for check-specific settings.
-    if (isset($form['advanced']['check_specific'])) {
-      $check_specific_values = $form_state->getValue('check_specific');
-      foreach ($this->checklist->getChecks() as $check) {
-        $check_form = &$form['advanced']['check_specific'][$check->id()];
-        if (isset($check_form)) {
-          $check->settings()
-            ->validateForm($check_form, $check_specific_values[$check->id()]);
-        }
-      }
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    // Frequently used configuration items.
-    $check_settings = $this->config('security_review.checks');
-
-    // Save that the module has been configured.
-    $this->securityReview->setConfigured(TRUE);
-
-    // Save the new untrusted roles.
-    $untrusted_roles = array_keys(array_filter($form_state->getValue('untrusted_roles')));
-    $this->securityReview->setUntrustedRoles($untrusted_roles);
-
-    // Save the new logging setting.
-    $logging = $form_state->getValue('logging') == 1;
-    $this->securityReview->setLogging($logging);
-
-    // Skip selected checks.
-    $skipped = array_keys(array_filter($form_state->getValue('skip')));
-    foreach ($this->checklist->getChecks() as $check) {
-      if (in_array($check->id(), $skipped)) {
-        $check->skip();
-      }
-      else {
-        $check->enable();
-      }
-    }
-
-    // Save the check-specific settings.
-    if (isset($form['advanced']['check_specific'])) {
-      $check_specific_values = $form_state->getValue('check_specific');
-      foreach ($check_specific_values as $id => $values) {
-        // Get corresponding Check.
-        $check = $this->checklist->getCheckById($id);
-
-        // Submit parameters.
-        $check_form = &$form['advanced']['check_specific'][$id]['form'];
-        $check_form_values = $check_specific_values[$id]['form'];
-
-        // Submit.
-        $check->settings()->submitForm($check_form, $check_form_values);
-      }
-    }
-
-    // Commit the settings.
-    $check_settings->save();
-
-    // Finish submitting the form.
-    parent::submitForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getEditableConfigNames() {
-    return ['security_review.checks'];
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Security.php b/web/modules/contrib/security_review/src/Security.php
deleted file mode 100644 (file)
index 3104c86..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\DrupalKernelInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\user\Entity\Role;
-
-/**
- * Provides frequently used security-related data.
- */
-class Security {
-
-  use DependencySerializationTrait;
-
-  /**
-   * The config factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
-   * The Drupal kernel.
-   *
-   * @var \Drupal\Core\DrupalKernelInterface
-   */
-  protected $kernel;
-
-  /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * The security_review service.
-   *
-   * @var \Drupal\security_review\SecurityReview
-   */
-  protected $securityReview;
-
-  /**
-   * Constructs a Security instance.
-   *
-   * @param \Drupal\security_review\SecurityReview $security_review
-   *   The SecurityReview service.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory.
-   * @param \Drupal\Core\DrupalKernelInterface $kernel
-   *   The Drupal kernel.
-   */
-  public function __construct(SecurityReview $security_review, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, DrupalKernelInterface $kernel) {
-    // Store the dependencies.
-    $this->securityReview = $security_review;
-    $this->moduleHandler = $module_handler;
-    $this->configFactory = $config_factory;
-    $this->kernel = $kernel;
-  }
-
-  /**
-   * Returns the IDs of untrusted roles.
-   *
-   * If the module hasn't been configured yet, it returns the default untrusted
-   * roles.
-   *
-   * @return string[]
-   *   Untrusted roles' IDs.
-   */
-  public function untrustedRoles() {
-    // If the module hasn't been manually configured yet, return the untrusted
-    // roles depending on Drupal's actual configuration.
-    if (!$this->securityReview->isConfigured()) {
-      return static::defaultUntrustedRoles();
-    }
-
-    // Else return the stored untrusted roles.
-    return $this->securityReview->getUntrustedRoles();
-  }
-
-  /**
-   * Returns the default untrusted roles.
-   *
-   * The default untrusted roles are:
-   *   Anonymous      : always
-   *   Authenticated  : if visitors are allowed to create accounts.
-   *
-   * @return string[]
-   *   Default untrusted roles' IDs.
-   */
-  public function defaultUntrustedRoles() {
-    // Add the Anonymous role to the output array.
-    $roles = [AccountInterface::ANONYMOUS_ROLE];
-
-    // Check whether visitors can create accounts.
-    $user_register = $this->configFactory->get('user.settings')
-      ->get('register');
-    if ($user_register !== USER_REGISTER_ADMINISTRATORS_ONLY) {
-      // If visitors are allowed to create accounts they are considered
-      // untrusted.
-      $roles[] = AccountInterface::AUTHENTICATED_ROLE;
-    }
-
-    // Return the untrusted roles.
-    return $roles;
-  }
-
-  /**
-   * Returns the permission strings that a group of roles have.
-   *
-   * @param string[] $role_ids
-   *   The array of roleIDs to check.
-   * @param bool $group_by_role_id
-   *   Choose whether to group permissions by role ID.
-   *
-   * @return array
-   *   An array of the permissions untrusted roles have. If $groupByRoleId is
-   *   true, the array key is the role ID, the value is the array of permissions
-   *   the role has.
-   */
-  public function rolePermissions(array $role_ids, $group_by_role_id = FALSE) {
-    // Get the permissions the given roles have, grouped by roles.
-    $permissions_grouped = user_role_permissions($role_ids);
-
-    // Fill up the administrative roles' permissions too.
-    foreach ($role_ids as $role_id) {
-      $role = Role::load($role_id);
-      /** @var Role $role */
-      if ($role->isAdmin()) {
-        $permissions_grouped[$role_id] = $this->permissions();
-      }
-    }
-
-    if ($group_by_role_id) {
-      // If the result should be grouped, we have nothing else to do.
-      return $permissions_grouped;
-    }
-    else {
-      // Merge the grouped permissions into $untrusted_permissions.
-      $untrusted_permissions = [];
-      foreach ($permissions_grouped as $permissions) {
-        $untrusted_permissions = array_merge($untrusted_permissions, $permissions);
-      }
-
-      // Remove duplicate elements and fix indexes.
-      $untrusted_permissions = array_values(array_unique($untrusted_permissions));
-      return $untrusted_permissions;
-    }
-  }
-
-  /**
-   * Returns the permission strings that untrusted roles have.
-   *
-   * @param bool $group_by_role_id
-   *   Choose whether to group permissions by role ID.
-   *
-   * @return array
-   *   An array of the permissions untrusted roles have. If $groupByRoleId is
-   *   true, the array key is the role ID, the value is the array of permissions
-   *   the role has.
-   */
-  public function untrustedPermissions($group_by_role_id = FALSE) {
-    return $this->rolePermissions($this->untrustedRoles(), $group_by_role_id);
-  }
-
-  /**
-   * Returns the trusted roles.
-   *
-   * @return array
-   *   Trusted roles' IDs.
-   */
-  public function trustedRoles() {
-    // Get the stored/default untrusted roles.
-    $untrusted_roles = $this->untrustedRoles();
-
-    // Iterate through all the roles, and store which are not untrusted.
-    $trusted = [];
-    foreach (user_roles() as $role) {
-      if (!in_array($role->id(), $untrusted_roles)) {
-        $trusted[] = $role->id();
-      }
-    }
-
-    // Return the trusted roles.
-    return $trusted;
-  }
-
-  /**
-   * Returns the permission strings that trusted roles have.
-   *
-   * @param bool $group_by_role_id
-   *   Choose whether to group permissions by role ID.
-   *
-   * @return array
-   *   An array of the permissions trusted roles have. If $groupByRoleId is
-   *   true, the array key is the role ID, the value is the array of permissions
-   *   the role has.
-   */
-  public function trustedPermissions($group_by_role_id = FALSE) {
-    return $this->rolePermissions($this->trustedRoles(), $group_by_role_id);
-  }
-
-
-  /**
-   * Gets all the permissions.
-   *
-   * @param bool $meta
-   *   Whether to return only permission strings or metadata too.
-   *
-   * @see \Drupal\user\PermissionHandlerInterface::getPermissions()
-   *
-   * @return array
-   *   Array of every permission.
-   */
-  public function permissions($meta = FALSE) {
-    // Not injected because of hard testability.
-    $permissions = \Drupal::service('user.permissions')->getPermissions();
-
-    if (!$meta) {
-      return array_keys($permissions);
-    }
-    return $permissions;
-  }
-
-  /**
-   * Gets the list of unsafe HTML tags.
-   *
-   * @return string[]
-   *   List of unsafe tags.
-   */
-  public function unsafeTags() {
-    $unsafe_tags = [
-      'applet',
-      'area',
-      'audio',
-      'base',
-      'basefont',
-      'body',
-      'button',
-      'comment',
-      'embed',
-      'eval',
-      'form',
-      'frame',
-      'frameset',
-      'head',
-      'html',
-      'iframe',
-      'image',
-      'img',
-      'input',
-      'isindex',
-      'label',
-      'link',
-      'map',
-      'math',
-      'meta',
-      'noframes',
-      'noscript',
-      'object',
-      'optgroup',
-      'option',
-      'param',
-      'script',
-      'select',
-      'style',
-      'svg',
-      'table',
-      'td',
-      'textarea',
-      'title',
-      'video',
-      'vmlframe',
-    ];
-
-    // Alter data.
-    $this->moduleHandler->alter('security_review_unsafe_tags', $unsafe_tags);
-
-    return $unsafe_tags;
-  }
-
-  /**
-   * Gets the list of unsafe file extensions.
-   *
-   * @return string[]
-   *   List of unsafe extensions.
-   */
-  public function unsafeExtensions() {
-    $unsafe_ext = [
-      'swf',
-      'exe',
-      'html',
-      'htm',
-      'php',
-      'phtml',
-      'py',
-      'js',
-      'vb',
-      'vbe',
-      'vbs',
-    ];
-
-    // Alter data.
-    $this->moduleHandler
-      ->alter('security_review_unsafe_extensions', $unsafe_ext);
-
-    return $unsafe_ext;
-  }
-
-  /**
-   * Returns the site path.
-   *
-   * @return string
-   *   Absolute site path.
-   */
-  public function sitePath() {
-    return DRUPAL_ROOT . '/' . $this->kernel->getSitePath();
-  }
-
-  /**
-   * Finds files and directories that are writable by the web server.
-   *
-   * @param string[] $files
-   *   The files to iterate through.
-   * @param bool $cli
-   *   Whether it is being invoked in CLI context.
-   *
-   * @return string[]
-   *   The files that are writable.
-   */
-  public function findWritableFiles(array $files, $cli = FALSE) {
-    $writable = [];
-    if (!$cli) {
-      // Running from UI.
-      foreach ($files as $file) {
-        if (is_writable($file)) {
-          $writable[] = $file;
-        }
-      }
-    }
-    else {
-      // Get the web server's user data.
-      $uid = $this->securityReview->getServerUid();
-      $gids = $this->securityReview->getServerGids();
-
-      foreach ($files as $file) {
-        $perms = 0777 & fileperms($file);
-        // Check write permissions for others.
-        $ow = ($perms >> 1) & 1;
-        if ($ow === 1) {
-          $writable[] = $file;
-          continue;
-        }
-
-        // Check write permissions for owner.
-        $uw = ($perms >> 7) & 1;
-        if ($uw === 1 && fileowner($file) == $uid) {
-          $writable[] = $file;
-          continue;
-        }
-
-        // Check write permissions for group.
-        $gw = ($perms >> 4) & 1;
-        if ($gw === 1 && in_array(filegroup($file), $gids)) {
-          $writable[] = $file;
-        }
-      }
-    }
-    return $writable;
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/SecurityReview.php b/web/modules/contrib/security_review/src/SecurityReview.php
deleted file mode 100644 (file)
index fafaa9c..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-<?php
-
-namespace Drupal\security_review;
-
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\Session\AccountProxyInterface;
-use Drupal\Core\State\StateInterface;
-
-/**
- * A class containing static methods regarding the module's configuration.
- */
-class SecurityReview {
-
-  use DependencySerializationTrait;
-
-  /**
-   * Temporary logging setting.
-   *
-   * @var null|bool
-   */
-  protected static $temporaryLogging = NULL;
-
-  /**
-   * The config factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
-   * The config storage.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected $config;
-
-  /**
-   * The state storage.
-   *
-   * @var \Drupal\Core\State\StateInterface
-   */
-  protected $state;
-
-  /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected $currentUser;
-
-  /**
-   * Constructs a SecurityReview instance.
-   *
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory.
-   * @param \Drupal\Core\State\StateInterface $state
-   *   The state storage.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
-   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
-   *   The current user.
-   */
-  public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, ModuleHandlerInterface $module_handler, AccountProxyInterface $current_user) {
-    // Store the dependencies.
-    $this->configFactory = $config_factory;
-    $this->config = $config_factory->getEditable('security_review.settings');
-    $this->state = $state;
-    $this->moduleHandler = $module_handler;
-    $this->currentUser = $current_user;
-  }
-
-  /**
-   * Returns whether the module has been configured.
-   *
-   * If the module has been configured on the settings page this function
-   * returns true. Otherwise it returns false.
-   *
-   * @return bool
-   *   A boolean indicating whether the module has been configured.
-   */
-  public function isConfigured() {
-    return $this->config->get('configured') === TRUE;
-  }
-
-  /**
-   * Returns true if logging is enabled, otherwise returns false.
-   *
-   * @return bool
-   *   A boolean indicating whether logging is enabled.
-   */
-  public function isLogging() {
-    // Check for temporary logging.
-    if (static::$temporaryLogging !== NULL) {
-      return static::$temporaryLogging;
-    }
-
-    return $this->config->get('log') === TRUE;
-  }
-
-  /**
-   * Returns the last time Security Review has been run.
-   *
-   * @return int
-   *   The last time Security Review has been run.
-   */
-  public function getLastRun() {
-    return $this->state->get('last_run', 0);
-  }
-
-  /**
-   * Returns the IDs of the stored untrusted roles.
-   *
-   * @return string[]
-   *   Stored untrusted roles' IDs.
-   */
-  public function getUntrustedRoles() {
-    return $this->config->get('untrusted_roles');
-  }
-
-  /**
-   * Sets the 'configured' flag.
-   *
-   * @param bool $configured
-   *   The new value of the 'configured' setting.
-   */
-  public function setConfigured($configured) {
-    $this->config->set('configured', $configured);
-    $this->config->save();
-  }
-
-  /**
-   * Sets the 'logging' flag.
-   *
-   * @param bool $logging
-   *   The new value of the 'logging' setting.
-   * @param bool $temporary
-   *   Whether to set only temporarily.
-   */
-  public function setLogging($logging, $temporary = FALSE) {
-    if (!$temporary) {
-      $this->config->set('log', $logging);
-      $this->config->save();
-    }
-    else {
-      static::$temporaryLogging = ($logging == TRUE);
-    }
-  }
-
-  /**
-   * Sets the 'last_run' value.
-   *
-   * @param int $last_run
-   *   The new value for 'last_run'.
-   */
-  public function setLastRun($last_run) {
-    $this->state->set('last_run', $last_run);
-  }
-
-  /**
-   * Stores the given 'untrusted_roles' setting.
-   *
-   * @param string[] $untrusted_roles
-   *   The new untrusted roles' IDs.
-   */
-  public function setUntrustedRoles(array $untrusted_roles) {
-    $this->config->set('untrusted_roles', $untrusted_roles);
-    $this->config->save();
-  }
-
-  /**
-   * Logs an event.
-   *
-   * @param \Drupal\security_review\Check $check
-   *   The Check the message is about.
-   * @param string $message
-   *   The message.
-   * @param array $context
-   *   The context of the message.
-   * @param int $level
-   *   Severity (RfcLogLevel).
-   */
-  public function log(Check $check, $message, array $context, $level) {
-    if (static::isLogging()) {
-      $this->moduleHandler->invokeAll(
-        'security_review_log',
-        [
-          'check' => $check,
-          'message' => $message,
-          'context' => $context,
-          'level' => $level,
-        ]
-      );
-    }
-  }
-
-  /**
-   * Logs a check result.
-   *
-   * @param \Drupal\security_review\CheckResult $result
-   *   The result to log.
-   */
-  public function logCheckResult(CheckResult $result = NULL) {
-    if ($this->isLogging()) {
-      if ($result == NULL) {
-        $check = $result->check();
-        $context = [
-          '@check' => $check->getTitle(),
-          '@namespace' => $check->getNamespace(),
-        ];
-        $this->log($check, '@check of @namespace produced a null result', $context, RfcLogLevel::CRITICAL);
-        return;
-      }
-
-      $check = $result->check();
-
-      // Fallback log message.
-      $level = RfcLogLevel::NOTICE;
-      $message = '@name check invalid result';
-
-      // Set log message and level according to result.
-      switch ($result->result()) {
-        case CheckResult::SUCCESS:
-          $level = RfcLogLevel::INFO;
-          $message = '@name check succeeded';
-          break;
-
-        case CheckResult::FAIL:
-          $level = RfcLogLevel::ERROR;
-          $message = '@name check failed';
-          break;
-
-        case CheckResult::WARN:
-          $level = RfcLogLevel::WARNING;
-          $message = '@name check raised a warning';
-          break;
-
-        case CheckResult::INFO:
-          $level = RfcLogLevel::INFO;
-          $message = '@name check returned info';
-          break;
-      }
-
-      $context = ['@name' => $check->getTitle()];
-      $this->log($check, $message, $context, $level);
-    }
-  }
-
-  /**
-   * Deletes orphaned check data.
-   */
-  public function cleanStorage() {
-    /** @var \Drupal\security_review\Checklist $checklist */
-    $checklist = \Drupal::service('security_review.checklist');
-
-    // Get list of check configuration names.
-    $orphaned = $this->configFactory->listAll('security_review.check.');
-
-    // Remove items that are used by the checks.
-    foreach ($checklist->getChecks() as $check) {
-      $key = array_search('security_review.check.' . $check->id(), $orphaned);
-      if ($key !== FALSE) {
-        unset($orphaned[$key]);
-      }
-    }
-
-    // Delete orphaned configuration data.
-    foreach ($orphaned as $config_name) {
-      $config = $this->configFactory->getEditable($config_name);
-      $config->delete();
-    }
-  }
-
-  /**
-   * Stores information about the server into the State system.
-   */
-  public function setServerData() {
-    if (!static::isServerPosix() || PHP_SAPI === 'cli') {
-      return;
-    }
-    // Determine web server's uid and groups.
-    $uid = posix_getuid();
-    $groups = posix_getgroups();
-
-    // Store the data in the State system.
-    $this->state->set('security_review.server.uid', $uid);
-    $this->state->set('security_review.server.groups', $groups);
-  }
-
-  /**
-   * Returns whether the server is POSIX.
-   *
-   * @return bool
-   *   Whether the web server is POSIX based.
-   */
-  public function isServerPosix() {
-    return function_exists('posix_getuid');
-  }
-
-  /**
-   * Returns the UID of the web server.
-   *
-   * @return int
-   *   UID of the web server's user.
-   */
-  public function getServerUid() {
-    return $this->state->get('security_review.server.uid');
-  }
-
-  /**
-   * Returns the GIDs of the web server.
-   *
-   * @return int[]
-   *   GIDs of the web server's user.
-   */
-  public function getServerGids() {
-    return $this->state->get('security_review.server.groups');
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Tests/CheckWebTest.php b/web/modules/contrib/security_review/src/Tests/CheckWebTest.php
deleted file mode 100644 (file)
index 1f8a452..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Contains tests for Check that don't suffice with KernelTestBase.
- *
- * @group security_review
- */
-class CheckWebTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['security_review'];
-
-  /**
-   * The security checks defined by Security Review.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $checks;
-
-  /**
-   * The test user.
-   *
-   * @var \Drupal\user\Entity\User
-   */
-  protected $user;
-
-  /**
-   * Sets up the testing environment, logs the user in, populates $check.
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    // Login.
-    $this->user = $this->drupalCreateUser(
-      [
-        'run security checks',
-        'access security review list',
-        'access administration pages',
-        'administer site configuration',
-      ]
-    );
-    $this->drupalLogin($this->user);
-
-    // Get checks.
-    $this->checks = security_review_security_review_checks();
-  }
-
-  /**
-   * Tests Check::skip().
-   *
-   * Checks whether skip() marks the check as skipped, and checks the
-   * skippedBy() value.
-   */
-  public function testSkipCheck() {
-    foreach ($this->checks as $check) {
-      $check->skip();
-
-      $is_skipped = $check->isSkipped();
-      $skipped_by = $check->skippedBy();
-
-      $this->assertTrue($is_skipped, $check->getTitle() . ' skipped.');
-      $this->assertEqual($this->user->id(), $skipped_by->id(), 'Skipped by ' . $skipped_by->label());
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/src/Tests/ChecklistWebTest.php b/web/modules/contrib/security_review/src/Tests/ChecklistWebTest.php
deleted file mode 100644 (file)
index dead358..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-
-namespace Drupal\security_review\Tests;
-
-use Drupal\security_review\Checklist;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Contains tests related to the SecurityReview class.
- *
- * @group security_review
- */
-class ChecklistWebTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['security_review'];
-
-  /**
-   * The test user.
-   *
-   * @var \Drupal\user\Entity\User
-   */
-  protected $user;
-
-  /**
-   * The security checks defined by Security Review.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $checks;
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * Sets up the testing environment.
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->checklist = \Drupal::getContainer()
-      ->get('security_review.checklist');
-
-    // Login.
-    $this->user = $this->drupalCreateUser(
-      [
-        'run security checks',
-        'access security review list',
-        'access administration pages',
-        'administer site configuration',
-      ]
-    );
-    $this->drupalLogin($this->user);
-
-    // Populate $checks.
-    $this->checks = security_review_security_review_checks();
-
-    // Clear cache.
-    Checklist::clearCache();
-  }
-
-  /**
-   * Tests a full checklist run.
-   *
-   * Tests whether the checks hasn't been run yet, then runs them and checks
-   * that their lastRun value is not 0.
-   */
-  public function testRun() {
-    foreach ($this->checks as $check) {
-      $this->assertEqual(0, $check->lastRun(), $check->getTitle() . ' has not been run yet.');
-    }
-    $this->checklist->runChecklist();
-    foreach ($this->checks as $check) {
-      $this->assertNotEqual(0, $check->lastRun(), $check->getTitle() . ' has been run.');
-    }
-  }
-
-  /**
-   * Skips all checks then runs the checklist. No checks should be ran.
-   */
-  public function testSkippedRun() {
-    foreach ($this->checks as $check) {
-      $check->skip();
-    }
-    $this->checklist->runChecklist();
-    foreach ($this->checks as $check) {
-      $this->assertEqual(0, $check->lastRun(), $check->getTitle() . ' has not been run.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/templates/check_evaluation.html.twig b/web/modules/contrib/security_review/templates/check_evaluation.html.twig
deleted file mode 100644 (file)
index 77f4509..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-{#
-/**
- * @file
- * Default evaluation page template for checks.
- *
- * Available variables:
- * - paragraphs: Array of paragraphs (strings) to show before the list.
- * - items: Array of items (strings) to show in an unordered list after the paragraphs.
- */
-#}
-
-{% for paragraph in paragraphs %}
-    <p>
-        {{ paragraph }}
-    </p>
-{% endfor %}
-{% if items is not empty %}
-    <ul>
-        {% for item in items %}
-            <li>{{ item }}</li>
-        {% endfor %}
-    </ul>
-{% endif %}
diff --git a/web/modules/contrib/security_review/templates/check_help.html.twig b/web/modules/contrib/security_review/templates/check_help.html.twig
deleted file mode 100644 (file)
index 8b491cf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{#
-/**
- * @file
- * Default check-specific help page template for checks.
- *
- * Available variables:
- * - title: The title to show on the top of the page.
- * - paragraphs: Array of paragraphs (strings) to show after the title.
- */
-#}
-
-<h3>
-    {{ title }}
-</h3>
-{% for paragraph in paragraphs %}
-    <p>
-        {{ paragraph }}
-    </p>
-{% endfor %}
diff --git a/web/modules/contrib/security_review/templates/general_help.html.twig b/web/modules/contrib/security_review/templates/general_help.html.twig
deleted file mode 100644 (file)
index 0b0168e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-{#
-/**
- * @file
- * Default general help page of Security Review.
- *
- * Available variables:
- * - paragraphs: Array of paragraphs (strings) to show as an introduction.
- * - items: Array of items (strings) to show in an unordered list after the
- *   paragraphs.
- * - checks: Array of check links grouped by their namespaces.
- */
-#}
-
-{% for paragraph in paragraphs %}
-    <p>
-        {{ paragraph }}
-    </p>
-{% endfor %}
-<h3>
-    {% trans %}
-    Check-specific help
-    {% endtrans %}
-</h3>
-<p>
-    {% trans %}
-    Details and help on the security review checks. Checks are not always
-    perfectly correct in their procedure and result. Refer to drupal.org
-    handbook documentation if you are unsure how to make the recommended
-    alterations to your configuration or consult the module's README.txt for
-    support.
-    {% endtrans %}
-</p>
-{% if checks is not empty %}
-    {% for check_namespace in checks %}
-        <h4>{{ check_namespace.namespace }}</h4>
-        <ul>
-            {% for check_link in check_namespace.check_links %}
-                <li>{{ check_link }}</li>
-            {% endfor %}
-        </ul>
-    {% endfor %}
-{% endif %}
diff --git a/web/modules/contrib/security_review/templates/run_and_review.html.twig b/web/modules/contrib/security_review/templates/run_and_review.html.twig
deleted file mode 100644 (file)
index e6eac92..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-{#
-/**
- * @file
- * Default template for the Run & Review page.
- *
- * Available variables:
- * - checks: Array of check informations.
- *   A check information consists of:
- *   - result: The check's result (string).
- *   - message: The result message.
- *   - help_link: The link to the check's help page.
- *   - toggle_link: The toggle link for the check.
- *   - skipped: Whether the check is skipped.
- */
-#}
-
-<h3>
-    {% trans %}
-    Review results from last run {{ date }}
-    {% endtrans %}
-</h3>
-<p>
-    {% trans %}
-    Here you can review the results from the last run of the checklist. Checks
-    are not always perfectly correct in their procedure and result. You can keep
-    a check from running by clicking the 'Skip' link beside it. You can run the
-    checklist again by expanding the fieldset above.
-    {% endtrans %}
-</p>
-<table class="security-review-run-and-review__table">
-    <tbody>
-    {% for check in checks %}
-        {% set style = '' %}
-        {% if check.result is defined %}
-            {% set style = style ~ ' ' ~ check.result %}
-        {% endif %}
-        {% if check.skipped %}
-            {% set style = style ~ ' skipped' %}
-        {% endif %}
-        <tr class="security-review-run-and-review__entry{{ style }}">
-            <td class="security-review-run-and-review__entry-icon">
-                {% if icons[check.result] is defined %}
-                    <img src="{{ icons[check.result] }}"/>
-                {% endif %}
-            </td>
-            <td>{{ check.message }}</td>
-            <td>{{ check.help_link }}</td>
-            <td class="security-review-toggle-link">{{ check.toggle_link }}</td>
-        </tr>
-    {% endfor %}
-    </tbody>
-</table>
diff --git a/web/modules/contrib/security_review/tests/modules/security_review_test/security_review_test.info.yml b/web/modules/contrib/security_review/tests/modules/security_review_test/security_review_test.info.yml
deleted file mode 100644 (file)
index 5aeb68c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-name: security_review_test
-type: module
-core: 8.x
-package: Testing
-dependencies:
-  - security_review
diff --git a/web/modules/contrib/security_review/tests/modules/security_review_test/security_review_test.module b/web/modules/contrib/security_review/tests/modules/security_review_test/security_review_test.module
deleted file mode 100644 (file)
index ae4400f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-/**
- * @file
- * Module that defines testable security checks for Security Review.
- */
-
-use Drupal\security_review_test\Test;
-use Drupal\security_review_test\TestNoStore;
-
-/**
- * Implements hook_security_review_checks().
- */
-function security_review_test_security_review_checks() {
-  return [
-    new Test(),
-    new TestNoStore(),
-  ];
-}
diff --git a/web/modules/contrib/security_review/tests/modules/security_review_test/src/Test.php b/web/modules/contrib/security_review/tests/modules/security_review_test/src/Test.php
deleted file mode 100644 (file)
index 4b0bf65..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace Drupal\security_review_test;
-
-use Drupal\security_review\Check;
-use Drupal\security_review\CheckResult;
-
-/**
- * A test security check for testing extensibility.
- */
-class Test extends Check {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getNamespace() {
-    return 'Security Review Test';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Test';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function run() {
-    $findings = [];
-    for ($i = 0; $i < 20; ++$i) {
-      $findings[] = rand(0, 1) ? rand(0, 10) : 'string';
-    }
-
-    return $this->createResult(CheckResult::INFO, $findings);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function help() {
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMessage($result_const) {
-    return 'The test ran.';
-  }
-
-}
diff --git a/web/modules/contrib/security_review/tests/modules/security_review_test/src/TestNoStore.php b/web/modules/contrib/security_review/tests/modules/security_review_test/src/TestNoStore.php
deleted file mode 100644 (file)
index 15a04cf..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace Drupal\security_review_test;
-
-/**
- * A test security check for testing extensibility.
- *
- * Same as Test, but doesn't store findings.
- */
-class TestNoStore extends Test {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTitle() {
-    return 'Test without storing findings';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function storesFindings() {
-    return FALSE;
-  }
-
-}
diff --git a/web/modules/contrib/security_review/tests/src/Kernel/CheckTest.php b/web/modules/contrib/security_review/tests/src/Kernel/CheckTest.php
deleted file mode 100644 (file)
index 72676e4..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-<?php
-
-namespace Drupal\Tests\security_review\Kernel;
-
-use Drupal\KernelTests\KernelTestBase;
-use Drupal\security_review\CheckResult;
-
-/**
- * Contains tests for Checks.
- *
- * @group security_review
- */
-class CheckTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['security_review', 'security_review_test'];
-
-  /**
-   * The security checks defined by Security Review and Security Review Test.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $checks;
-
-  /**
-   * The security checks defined by Security Review.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $realChecks;
-
-  /**
-   * The security checks defined by Security Review Test.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $testChecks;
-
-  /**
-   * Sets up the environment, populates the $checks variable.
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->realChecks = security_review_security_review_checks();
-    $this->testChecks = security_review_test_security_review_checks();
-    $this->checks = array_merge($this->realChecks, $this->testChecks);
-  }
-
-  /**
-   * Tests whether $checks is empty.
-   */
-  public function testChecksExist() {
-    $this->assertFalse(empty($this->checks), 'Checks found.');
-  }
-
-  /**
-   * Every check should be enabled by default.
-   */
-  public function testEnabledByDefault() {
-    foreach ($this->checks as $check) {
-      $this->assertFalse($check->isSkipped(), $check->getTitle() . ' is enabled by default.');
-    }
-  }
-
-  /**
-   * Tests some check's results on a clean install of Drupal.
-   */
-  public function testDefaultResults() {
-    $defaults = [
-      'security_review-field' => CheckResult::SUCCESS,
-    ];
-
-    foreach ($this->checks as $check) {
-      if (array_key_exists($check->id(), $defaults)) {
-        $result = $check->run();
-        $this->assertEquals($defaults[$check->id()], $result->result(), $check->getTitle() . ' produced the right result.');
-      }
-    }
-  }
-
-  /**
-   * Tests the storing of a check result on every test check.
-   */
-  public function testStoreResult() {
-    foreach ($this->testChecks as $check) {
-      // Run the check and store its result.
-      $result = $check->run();
-      $check->storeResult($result);
-
-      // Compare lastResult() with $result.
-      $last_result = $check->lastResult(TRUE);
-      $this->assertEquals($result->result(), $last_result->result(), 'Result stored.');
-      $this->assertEquals($result->time(), $last_result->time(), 'Time stored.');
-      if ($check->storesFindings()) {
-        // If storesFindings() is set to FALSE, then these could differ.
-        $this->assertEquals($result->findings(), $last_result->findings(), 'Findings stored.');
-      }
-    }
-  }
-
-  /**
-   * Tests stored result correction on lastResult() call.
-   *
-   * Tests the case when the check doesn't store its findings, and the new
-   * result that lastResult() returns overwrites the old one if the result
-   * integer is not the same.
-   */
-  public function testLastResultUpdate() {
-    foreach ($this->testChecks as $check) {
-      if (!$check->storesFindings()) {
-        // Get the real result.
-        $result = $check->run();
-
-        // Build the fake result.
-        $new_result_result = $result->result() == CheckResult::SUCCESS ? CheckResult::FAIL : CheckResult::SUCCESS;
-        $new_result = new CheckResult(
-          $check,
-          $new_result_result,
-          [],
-          TRUE
-        );
-
-        // Store it.
-        $check->storeResult($new_result);
-
-        // Check if lastResult()'s result integer is the same as $result's.
-        $last_result = $check->lastResult(TRUE);
-        $this->assertEquals($result->result(), $last_result->result(), 'Invalid result got updated.');
-      }
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/tests/src/Kernel/ChecklistTest.php b/web/modules/contrib/security_review/tests/src/Kernel/ChecklistTest.php
deleted file mode 100644 (file)
index 6172adc..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-
-namespace Drupal\Tests\security_review\Kernel;
-
-use Drupal\KernelTests\KernelTestBase;
-use Drupal\security_review\Checklist;
-
-/**
- * Contains test for Checklist.
- *
- * @group security_review
- */
-class ChecklistTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['security_review', 'security_review_test'];
-
-  /**
-   * The security_review.checklist service.
-   *
-   * @var \Drupal\security_review\Checklist
-   */
-  protected $checklist;
-
-  /**
-   * The security checks defined by Security Review and Security Review Test.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $checks;
-
-  /**
-   * The security checks defined by Security Review.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $realChecks;
-
-  /**
-   * The security checks defined by Security Review Test.
-   *
-   * @var \Drupal\security_review\Check[]
-   */
-  protected $testChecks;
-
-  /**
-   * Array of the IDs of $checks.
-   *
-   * @var array
-   */
-  protected $checkIDs;
-
-  /**
-   * Sets up the environment, populates the $checks variable.
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->checklist = \Drupal::getContainer()
-      ->get('security_review.checklist');
-    $this->realChecks = security_review_security_review_checks();
-    $this->testChecks = security_review_test_security_review_checks();
-    $this->checks = array_merge($this->realChecks, $this->testChecks);
-
-    Checklist::clearCache();
-    $this->checkIDs = [];
-    foreach ($this->checks as $check) {
-      $this->checkIDs[] = $check->id();
-    }
-  }
-
-  /**
-   * Tests Checklist::getChecks().
-   *
-   * Tests whether getChecks() contains all the checks that
-   * security_review_security_review_checks() and
-   * security_review_test_security_review_checks() returns.
-   */
-  public function testChecksProvided() {
-    foreach ($this->checklist->getChecks() as $check) {
-      $this->assertTrue(in_array($check->id(), $this->checkIDs), $check->getTitle() . ' found.');
-    }
-  }
-
-  /**
-   * Tests whether checks returned by getEnabledChecks() are all enabled.
-   */
-  public function testEnabledChecks() {
-    foreach ($this->checklist->getEnabledChecks() as $check) {
-      $this->assertFalse($check->isSkipped(), $check->getTitle() . ' is enabled.');
-
-      // Disable check.
-      $check->skip();
-    }
-    Checklist::clearCache();
-    $this->assertEquals(0, count($this->checklist->getEnabledChecks()), 'Disabled all checks.');
-  }
-
-  /**
-   * Tests Checklist's Check search functions.
-   *
-   * Tests the search functions of Checklist:
-   *   getCheck().
-   *   getCheckById().
-   */
-  public function testCheckSearch() {
-    foreach ($this->checklist->getChecks() as $check) {
-      // getCheck().
-      $found = $this->checklist->getCheck($check->getMachineNamespace(), $check->getMachineTitle());
-      $this->assertEquals($check->id(), $found->id(), 'Found ' . $check->getTitle() . '.');
-
-      // getCheckById().
-      $found = $this->checklist->getCheckById($check->id());
-      $this->assertEquals($check->id(), $found->id(), 'Found ' . $check->getTitle() . '.');
-    }
-  }
-
-}
diff --git a/web/modules/contrib/security_review/tests/src/Kernel/SecurityReviewTest.php b/web/modules/contrib/security_review/tests/src/Kernel/SecurityReviewTest.php
deleted file mode 100644 (file)
index 08066fa..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-namespace Drupal\Tests\security_review\Kernel;
-
-use Drupal\KernelTests\KernelTestBase;
-
-/**
- * Contains tests related to the SecurityReview class.
- *
- * @group security_review
- */
-class SecurityReviewTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['security_review'];
-
-  /**
-   * The security_review service.
-   *
-   * @var \Drupal\security_review\SecurityReview
-   */
-  protected $securityReview;
-
-  /**
-   * Sets up the testing environment.
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installConfig(static::$modules);
-    $this->securityReview = \Drupal::getContainer()->get('security_review');
-  }
-
-  /**
-   * Tests the 'logging' setting.
-   */
-  public function testConfigLogging() {
-    $this->assertTrue($this->securityReview->isLogging(), 'Logging enabled by default.');
-    $this->securityReview->setLogging(FALSE);
-    $this->assertFalse($this->securityReview->isLogging(), 'Logging disabled.');
-  }
-
-  /**
-   * Tests the 'configured' setting.
-   */
-  public function testConfigConfigured() {
-    $this->assertFalse($this->securityReview->isConfigured(), 'Not configured by default.');
-    $this->securityReview->setConfigured(TRUE);
-    $this->assertTrue($this->securityReview->isConfigured(), 'Set to configured.');
-  }
-
-  /**
-   * Tests the 'untrusted_roles' setting.
-   */
-  public function testConfigUntrustedRoles() {
-    $this->assertEquals([], $this->securityReview->getUntrustedRoles(), 'untrusted_roles empty by default.');
-
-    $roles = [0, 1, 2, 3, 4];
-    $this->securityReview->setUntrustedRoles($roles);
-    $this->assertEquals($roles, $this->securityReview->getUntrustedRoles(), 'untrusted_roles set to test array.');
-  }
-
-  /**
-   * Tests the 'last_run' setting.
-   */
-  public function testConfigLastRun() {
-    $this->assertEquals(0, $this->securityReview->getLastRun(), 'last_run is 0 by default.');
-    $time = time();
-    $this->securityReview->setLastRun($time);
-    $this->assertEquals($time, $this->securityReview->getLastRun(), 'last_run set to now.');
-  }
-
-}
index 0e7caa39ae694abdaf7a01f006d98735f9941aef..5bcecc267fabae54be86f51e9a3ea6751093e11c 100644 (file)
@@ -88,7 +88,7 @@
  * );
  * @endcode
  */
  * );
  * @endcode
  */
-$databases = array();
+$databases = [];
 
 /**
  * Customizing database settings.
 
 /**
  * Customizing database settings.
@@ -251,7 +251,7 @@ $databases = array();
  *   );
  * @endcode
  */
  *   );
  * @endcode
  */
-$config_directories = array();
+$config_directories = [];
 
 /**
  * Settings:
 
 /**
  * Settings:
@@ -263,23 +263,6 @@ $config_directories = array();
  * @see \Drupal\Core\Site\Settings::get()
  */
 
  * @see \Drupal\Core\Site\Settings::get()
  */
 
-/**
- * The active installation profile.
- *
- * Changing this after installation is not recommended as it changes which
- * directories are scanned during extension discovery. If this is set prior to
- * installation this value will be rewritten according to the profile selected
- * by the user.
- *
- * @see install_select_profile()
- *
- * @deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0. The
- *   install profile is written to the core.extension configuration. If a
- *   service requires the install profile use the 'install_profile' container
- *   parameter. Functional code can use \Drupal::installProfile().
- */
-# $settings['install_profile'] = '';
-
 /**
  * Salt for one-time login links, cancel links, form tokens, etc.
  *
 /**
  * Salt for one-time login links, cancel links, form tokens, etc.
  *
@@ -379,7 +362,7 @@ $settings['update_free_access'] = FALSE;
  * Specify every reverse proxy IP address in your environment.
  * This setting is required if $settings['reverse_proxy'] is TRUE.
  */
  * Specify every reverse proxy IP address in your environment.
  * This setting is required if $settings['reverse_proxy'] is TRUE.
  */
-# $settings['reverse_proxy_addresses'] = array('a.b.c.d', ...);
+# $settings['reverse_proxy_addresses'] = ['a.b.c.d', ...];
 
 /**
  * Set this value if your proxy server sends the client IP in a header
 
 /**
  * Set this value if your proxy server sends the client IP in a header
@@ -573,10 +556,10 @@ if ($settings['hash_salt']) {
  * The "en" part of the variable name, is dynamic and can be any langcode of
  * any added language. (eg locale_custom_strings_de for german).
  */
  * The "en" part of the variable name, is dynamic and can be any langcode of
  * any added language. (eg locale_custom_strings_de for german).
  */
-# $settings['locale_custom_strings_en'][''] = array(
+# $settings['locale_custom_strings_en'][''] = [
 #   'forum'      => 'Discussion board',
 #   '@count min' => '@count minutes',
 #   'forum'      => 'Discussion board',
 #   '@count min' => '@count minutes',
-# );
+# ];
 
 /**
  * A custom theme for the offline page:
 
 /**
  * A custom theme for the offline page:
@@ -630,7 +613,7 @@ if ($settings['hash_salt']) {
  *   override in a services.yml file in the same directory as settings.php
  *   (definitions in this file will override service definition defaults).
  */
  *   override in a services.yml file in the same directory as settings.php
  *   (definitions in this file will override service definition defaults).
  */
-# $settings['bootstrap_config_storage'] = array('Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage');
+# $settings['bootstrap_config_storage'] = ['Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage'];
 
 /**
  * Configuration overrides.
 
 /**
  * Configuration overrides.