Skip to content
This repository was archived by the owner on Oct 21, 2024. It is now read-only.

Commit 64cf5d0

Browse files
committed
add: initial files
1 parent 79d54c8 commit 64cf5d0

File tree

11 files changed

+779
-1
lines changed

11 files changed

+779
-1
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
.idea/laravel-html-purifier.iml
3+
.idea/misc.xml
4+
.idea/modules.xml
5+
.idea/php.xml
6+
.idea/vcs.xml
7+
.idea/workspace.xml

README.md

Lines changed: 203 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,204 @@
11
# laravel-html-purifier
2-
An HTML Purifier for Laravel
2+
An HTML Purifier for Laravel
3+
4+
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
5+
[![Software License][ico-license]](LICENSE)
6+
7+
A simple [Laravel](http://www.laravel.com/) service provider for easily using [HTMLPurifier](http://htmlpurifier.org/) inside Laravel. From their website:
8+
9+
> HTML Purifier is a standards-compliant HTML filter library written in PHP. HTML Purifier will not only remove all malicious code (better known as XSS) with a thoroughly audited, secure yet permissive whitelist, it will also make sure your documents are standards compliant, something only achievable with a comprehensive knowledge of W3C's specifications. Tired of using BBCode due to the current landscape of deficient or insecure HTML filters? Have a WYSIWYG editor but never been able to use it? Looking for high-quality, standards-compliant, open-source components for that application you're building? HTML Purifier is for you!
10+
11+
## Installation
12+
13+
### For Laravel 5.5+
14+
15+
Require this package with composer:
16+
```
17+
composer require hdvinnie/laravel-html-purifier
18+
```
19+
20+
The service provider will be auto-discovered. You do not need to add the provider anywhere.
21+
22+
### For Laravel 5.0 to 5.4
23+
24+
Require this package with composer:
25+
```
26+
composer require hdvinnie/laravel-html-purifier
27+
```
28+
29+
Find the `providers` key in `config/app.php` and register the HTMLPurifier Service Provider.
30+
31+
```php
32+
'providers' => [
33+
// ...
34+
HDVinnie\Purifier\PurifierServiceProvider::class,
35+
]
36+
```
37+
38+
Find the `aliases` key in `config/app.php` and register the Purifier alias.
39+
40+
```php
41+
'aliases' => [
42+
// ...
43+
'Purifier' => HDVinnie\Purifier\Facades\Purifier::class,
44+
]
45+
```
46+
47+
## Usage
48+
49+
50+
Use these methods inside your requests or middleware, wherever you need the HTML cleaned up:
51+
52+
```php
53+
\clean(Input::get('inputname'));
54+
```
55+
or
56+
57+
```php
58+
Purifier::clean(Input::get('inputname'));
59+
```
60+
61+
dynamic config
62+
```php
63+
\clean('This is my H1 title', 'titles');
64+
\clean('This is my H1 title', array('Attr.EnableID' => true));
65+
```
66+
or
67+
68+
```php
69+
Purifier::clean('This is my H1 title', 'titles');
70+
Purifier::clean('This is my H1 title', array('Attr.EnableID' => true));
71+
```
72+
73+
use [URI filter](http://htmlpurifier.org/docs/enduser-uri-filter.html)
74+
75+
```php
76+
Purifier::clean('This is my H1 title', 'titles', function (HTMLPurifier_Config $config) {
77+
$uri = $config->getDefinition('URI');
78+
$uri->addFilter(new HTMLPurifier_URIFilter_NameOfFilter(), $config);
79+
});
80+
```
81+
82+
Alternatively, in Laravel 7+, if you're looking to clean your HTML inside your Eloquent models, you can use our custom casts:
83+
84+
```php
85+
<?php
86+
87+
namespace App\Models;
88+
89+
use Illuminate\Database\Eloquent\Model;
90+
use HDVinnie\Purifier\Casts\CleanHtml;
91+
use HDVinnie\Purifier\Casts\CleanHtmlInput;
92+
use HDVinnie\Purifier\Casts\CleanHtmlOutput;
93+
94+
class User extends Model
95+
{
96+
protected $casts = [
97+
'bio' => CleanHtml::class, // cleans both when getting and setting the value
98+
'description' => CleanHtmlInput::class, // cleans when setting the value
99+
'history' => CleanHtmlOutput::class, // cleans when getting the value
100+
];
101+
}
102+
```
103+
104+
## Configuration
105+
106+
To use your own settings, publish config.
107+
108+
```
109+
php artisan vendor:publish --provider="HDVinnie\Purifier\PurifierServiceProvider"
110+
```
111+
112+
Config file `config/purifier.php` should like this
113+
114+
```php
115+
116+
return [
117+
'encoding' => 'UTF-8',
118+
'finalize' => true,
119+
'ignoreNonStrings' => false,
120+
'cachePath' => storage_path('app/purifier'),
121+
'cacheFileMode' => 0755,
122+
'settings' => [
123+
'default' => [
124+
'HTML.Doctype' => 'HTML 4.01 Transitional',
125+
'HTML.Allowed' => 'div,b,strong,i,em,u,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src]',
126+
'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align',
127+
'AutoFormat.AutoParagraph' => true,
128+
'AutoFormat.RemoveEmpty' => true,
129+
],
130+
'test' => [
131+
'Attr.EnableID' => 'true',
132+
],
133+
"youtube" => [
134+
"HTML.SafeIframe" => 'true',
135+
"URI.SafeIframeRegexp" => "%^(http://|https://|//)(www.youtube.com/embed/|player.vimeo.com/video/)%",
136+
],
137+
'custom_definition' => [
138+
'id' => 'html5-definitions',
139+
'rev' => 1,
140+
'debug' => false,
141+
'elements' => [
142+
// http://developers.whatwg.org/sections.html
143+
['section', 'Block', 'Flow', 'Common'],
144+
['nav', 'Block', 'Flow', 'Common'],
145+
['article', 'Block', 'Flow', 'Common'],
146+
['aside', 'Block', 'Flow', 'Common'],
147+
['header', 'Block', 'Flow', 'Common'],
148+
['footer', 'Block', 'Flow', 'Common'],
149+
150+
// Content model actually excludes several tags, not modelled here
151+
['address', 'Block', 'Flow', 'Common'],
152+
['hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common'],
153+
154+
// http://developers.whatwg.org/grouping-content.html
155+
['figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'],
156+
['figcaption', 'Inline', 'Flow', 'Common'],
157+
158+
// http://developers.whatwg.org/the-video-element.html#the-video-element
159+
['video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [
160+
'src' => 'URI',
161+
'type' => 'Text',
162+
'width' => 'Length',
163+
'height' => 'Length',
164+
'poster' => 'URI',
165+
'preload' => 'Enum#auto,metadata,none',
166+
'controls' => 'Bool',
167+
]],
168+
['source', 'Block', 'Flow', 'Common', [
169+
'src' => 'URI',
170+
'type' => 'Text',
171+
]],
172+
173+
// http://developers.whatwg.org/text-level-semantics.html
174+
['s', 'Inline', 'Inline', 'Common'],
175+
['var', 'Inline', 'Inline', 'Common'],
176+
['sub', 'Inline', 'Inline', 'Common'],
177+
['sup', 'Inline', 'Inline', 'Common'],
178+
['mark', 'Inline', 'Inline', 'Common'],
179+
['wbr', 'Inline', 'Empty', 'Core'],
180+
181+
// http://developers.whatwg.org/edits.html
182+
['ins', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
183+
['del', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
184+
],
185+
'attributes' => [
186+
['iframe', 'allowfullscreen', 'Bool'],
187+
['table', 'height', 'Text'],
188+
['td', 'border', 'Text'],
189+
['th', 'border', 'Text'],
190+
['tr', 'width', 'Text'],
191+
['tr', 'height', 'Text'],
192+
['tr', 'border', 'Text'],
193+
],
194+
],
195+
'custom_attributes' => [
196+
['a', 'target', 'Enum#_blank,_self,_target,_top'],
197+
],
198+
'custom_elements' => [
199+
['u', 'Inline', 'Inline', 'Common'],
200+
],
201+
],
202+
203+
];
204+
```

composer.json

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"name": "hdvinnie/laravel-html-purifier",
3+
"type": "package",
4+
"description": "An HTML Purifier for Laravel",
5+
"keywords": [
6+
"laravel",
7+
"html",
8+
"purifier",
9+
"security",
10+
"xss",
11+
"HDVinnie"
12+
],
13+
"homepage": "https://github.com/HDVinnie/laravel-html-purifier",
14+
"license": "MIT",
15+
"authors": [
16+
{
17+
"name": "HDVinnie",
18+
"email": "[email protected]",
19+
"homepage": "https://github.com/HDVinnie",
20+
"role": "Developer"
21+
}
22+
],
23+
"require": {
24+
"php": "^7.2|^8.0",
25+
"illuminate/config": "^5.8|^6.0|^7.0|^8.0|^9.0",
26+
"illuminate/support": "^5.8|^6.0|^7.0|^8.0|^9.0",
27+
"illuminate/filesystem": "^5.8|^6.0|^7.0|^8.0|^9.0",
28+
"ezyang/htmlpurifier": "4.13.*"
29+
},
30+
"require-dev": {
31+
"phpunit/phpunit": "^8.0|^9.0",
32+
"mockery/mockery": "^1.3.3",
33+
"graham-campbell/testbench": "^3.2|^5.5.1"
34+
},
35+
"suggest": {
36+
"laravel/framework": "To test the Laravel bindings",
37+
"laravel/lumen-framework": "To test the Lumen bindings"
38+
},
39+
"autoload": {
40+
"psr-4": {
41+
"HDVinnie\\Purifier\\": "src/"
42+
},
43+
"files": [
44+
"src/helpers.php"
45+
]
46+
},
47+
"autoload-dev": {
48+
"psr-4": {
49+
"HDVinnie\\Tests\\Purifier\\": "tests/"
50+
}
51+
},
52+
"extra": {
53+
"laravel": {
54+
"providers": [
55+
"HDVinnie\\Purifier\\PurifierServiceProvider"
56+
],
57+
"aliases": {
58+
"Purifier": "HDVinnie\\Purifier\\Facades\\Purifier"
59+
}
60+
}
61+
},
62+
"minimum-stability": "dev",
63+
"prefer-stable": true
64+
}

config/purifier.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
return [
4+
'encoding' => 'UTF-8',
5+
'finalize' => true,
6+
'ignoreNonStrings' => false,
7+
'cachePath' => storage_path('app/purifier'),
8+
'cacheFileMode' => 0755,
9+
'settings' => [
10+
'default' => [
11+
'HTML.Doctype' => 'HTML 4.01 Transitional',
12+
'HTML.Allowed' => 'div,b,strong,i,em,u,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src]',
13+
'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align',
14+
'AutoFormat.AutoParagraph' => true,
15+
'AutoFormat.RemoveEmpty' => true,
16+
],
17+
'test' => [
18+
'Attr.EnableID' => 'true',
19+
],
20+
"youtube" => [
21+
"HTML.SafeIframe" => 'true',
22+
"URI.SafeIframeRegexp" => "%^(http://|https://|//)(www.youtube.com/embed/|player.vimeo.com/video/)%",
23+
],
24+
'custom_definition' => [
25+
'id' => 'html5-definitions',
26+
'rev' => 1,
27+
'debug' => false,
28+
'elements' => [
29+
// http://developers.whatwg.org/sections.html
30+
['section', 'Block', 'Flow', 'Common'],
31+
['nav', 'Block', 'Flow', 'Common'],
32+
['article', 'Block', 'Flow', 'Common'],
33+
['aside', 'Block', 'Flow', 'Common'],
34+
['header', 'Block', 'Flow', 'Common'],
35+
['footer', 'Block', 'Flow', 'Common'],
36+
37+
// Content model actually excludes several tags, not modelled here
38+
['address', 'Block', 'Flow', 'Common'],
39+
['hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common'],
40+
41+
// http://developers.whatwg.org/grouping-content.html
42+
['figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'],
43+
['figcaption', 'Inline', 'Flow', 'Common'],
44+
45+
// http://developers.whatwg.org/the-video-element.html#the-video-element
46+
['video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [
47+
'src' => 'URI',
48+
'type' => 'Text',
49+
'width' => 'Length',
50+
'height' => 'Length',
51+
'poster' => 'URI',
52+
'preload' => 'Enum#auto,metadata,none',
53+
'controls' => 'Bool',
54+
]],
55+
['source', 'Block', 'Flow', 'Common', [
56+
'src' => 'URI',
57+
'type' => 'Text',
58+
]],
59+
60+
// http://developers.whatwg.org/text-level-semantics.html
61+
['s', 'Inline', 'Inline', 'Common'],
62+
['var', 'Inline', 'Inline', 'Common'],
63+
['sub', 'Inline', 'Inline', 'Common'],
64+
['sup', 'Inline', 'Inline', 'Common'],
65+
['mark', 'Inline', 'Inline', 'Common'],
66+
['wbr', 'Inline', 'Empty', 'Core'],
67+
68+
// http://developers.whatwg.org/edits.html
69+
['ins', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
70+
['del', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
71+
],
72+
'attributes' => [
73+
['iframe', 'allowfullscreen', 'Bool'],
74+
['table', 'height', 'Text'],
75+
['td', 'border', 'Text'],
76+
['th', 'border', 'Text'],
77+
['tr', 'width', 'Text'],
78+
['tr', 'height', 'Text'],
79+
['tr', 'border', 'Text'],
80+
],
81+
],
82+
'custom_attributes' => [
83+
['a', 'target', 'Enum#_blank,_self,_target,_top'],
84+
],
85+
'custom_elements' => [
86+
['u', 'Inline', 'Inline', 'Common'],
87+
],
88+
],
89+
90+
];

src/Casts/CleanHtml.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace HDVinnie\Purifier\Casts;
4+
5+
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
6+
7+
class CleanHtml implements CastsAttributes
8+
{
9+
/**
10+
* Clean the HTML when casting the given value.
11+
*/
12+
public function get(\Illuminate\Database\Eloquent\Model $model, string $key, $value, array $attributes): array
13+
{
14+
return clean($value);
15+
}
16+
17+
/**
18+
* Prepare the given value for storage by cleaning the HTML.
19+
*/
20+
public function set(\Illuminate\Database\Eloquent\Model $model, string $key, array $value, array $attributes): string
21+
{
22+
return clean($value);
23+
}
24+
}

0 commit comments

Comments
 (0)