├── .gitattributes
├── .gitignore
├── src
├── Scrubber
│ ├── ScrubberInterface.php
│ ├── BaseScrubber.php
│ ├── StripPhoneNumber.php
│ ├── Nullify.php
│ ├── Boolean.php
│ ├── NullIfRepeated.php
│ ├── StripCssAttributes.php
│ └── Html.php
├── MrClean.php
└── Sanitizer.php
├── package.json
├── tests
├── Fake
│ ├── Boolean.php
│ ├── TheWrapper.php
│ └── TheReplacer.php
├── TestCase.php
├── StripPhoneNumberTest.php
├── NullIfRepeatedTest.php
├── StripCssAttributesTest.php
├── NullifyTest.php
├── HtmlTest.php
├── RegisterTest.php
├── BooleanTest.php
├── CleanKeysTest.php
└── MrCleanTest.php
├── .travis.yml
├── composer.json
├── phpunit.xml
├── Gulpfile.js
├── .scrutinizer.yml
├── LICENSE.md
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.php filter=tabspace
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.phar
3 | composer.lock
4 | .DS_Store
5 | node_modules
6 | functional
7 | tags
8 |
--------------------------------------------------------------------------------
/src/Scrubber/ScrubberInterface.php:
--------------------------------------------------------------------------------
1 | value . '!';
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | cleaner = new \MrClean\MrClean;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/tests/Fake/TheReplacer.php:
--------------------------------------------------------------------------------
1 | value);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Scrubber/BaseScrubber.php:
--------------------------------------------------------------------------------
1 | value = $value;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Scrubber/StripPhoneNumber.php:
--------------------------------------------------------------------------------
1 | value );
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - hhvm
8 |
9 | before_script:
10 | - composer self-update
11 | - composer install --prefer-source --no-interaction --dev
12 |
13 | script:
14 | - phpunit --coverage-text --coverage-clover=coverage.clover
15 |
16 | after_script:
17 | - wget https://scrutinizer-ci.com/ocular.phar
18 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
19 |
--------------------------------------------------------------------------------
/src/Scrubber/Nullify.php:
--------------------------------------------------------------------------------
1 | value))) {
16 | return null;
17 | }
18 |
19 | return $this->value;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "joetannenbaum/mr-clean",
3 | "description": "",
4 | "keywords": [],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Joe Tannenbaum",
9 | "email": "hey@joe.codes"
10 | }
11 | ],
12 | "require": {
13 | "php": ">=5.4.0"
14 | },
15 | "require-dev": {
16 | "phpunit/phpunit": "4.1.*"
17 | },
18 | "autoload": {
19 | "psr-4": {
20 | "MrClean\\": "src/",
21 | "MrClean\\Test\\": "tests/"
22 | }
23 | },
24 | "minimum-stability": "stable"
25 | }
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
Is separate from this.
'; 14 | $dirty .= 'And this.
'; 15 | 16 | $result = $this->cleaner->scrubbers(['strip_css_attributes'])->scrub($dirty); 17 | 18 | $this->assertSame('This
Is separate from this.
And this.
', $result); 19 | } 20 | 21 | /** @test */ 22 | 23 | public function it_will_strip_css_attributes_with_single_quotes() 24 | { 25 | $dirty = "This
"; 26 | $dirty .= "Is separate from this.
"; 27 | $dirty .= "And this.
"; 28 | 29 | $result = $this->cleaner->scrubbers(['strip_css_attributes'])->scrub($dirty); 30 | 31 | $this->assertSame('This
Is separate from this.
And this.
', $result); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Joe Tannenbaum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/NullifyTest.php: -------------------------------------------------------------------------------- 1 | cleaner->scrubbers(['nullify']) 13 | ->scrub(''); 14 | 15 | $this->assertSame(null, $result); 16 | } 17 | 18 | /** @test */ 19 | 20 | public function it_will_nullify_a_whitespace_string() 21 | { 22 | $result = $this->cleaner->scrubbers(['nullify']) 23 | ->scrub(' '); 24 | 25 | $this->assertSame(null, $result); 26 | } 27 | 28 | /** @test */ 29 | 30 | public function it_will_not_nullify_a_non_empty_string() 31 | { 32 | $result = $this->cleaner->scrubbers(['nullify']) 33 | ->scrub('hi'); 34 | 35 | $this->assertSame('hi', $result); 36 | } 37 | 38 | /** @test */ 39 | 40 | public function it_will_not_nullify_an_empty_falsee_string() 41 | { 42 | $result = $this->cleaner->scrubbers(['nullify']) 43 | ->scrub(0); 44 | 45 | $this->assertSame(0, $result); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /tests/HtmlTest.php: -------------------------------------------------------------------------------- 1 | ThisIs separate from this.
'; 13 | 14 | $result = $this->cleaner->scrubbers(['html'])->scrub($dirty); 15 | 16 | $this->assertSame('This
Is separate from this.
', $result); 17 | } 18 | 19 | /** @test */ 20 | 21 | public function it_will_remove_empty_content_tags() 22 | { 23 | $dirty = 'This
This
', $result); 28 | } 29 | 30 | /** @test */ 31 | 32 | public function it_will_remove_repeated_opening_tags() 33 | { 34 | $dirty = 'This
'; 35 | 36 | $result = $this->cleaner->scrubbers(['html'])->scrub($dirty); 37 | 38 | $this->assertSame('This
', $result); 39 | } 40 | 41 | 42 | /** @test */ 43 | 44 | public function it_will_remove_repeated_closing_tags() 45 | { 46 | $dirty = 'This
'; 47 | 48 | $result = $this->cleaner->scrubbers(['html'])->scrub($dirty); 49 | 50 | $this->assertSame('This
', $result); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /tests/RegisterTest.php: -------------------------------------------------------------------------------- 1 | cleaner->register('MrClean\Test\Fake\TheReplacer'); 13 | 14 | $result = $this->cleaner->scrubbers(['the_replacer']) 15 | ->scrub('This is just full of some esses.'); 16 | 17 | $this->assertSame('Thim im jumt full of mome emmem.', $result); 18 | } 19 | 20 | /** @test */ 21 | 22 | public function it_can_register_a_new_cleaner_as_an_array() 23 | { 24 | $this->cleaner->register([ 25 | 'MrClean\Test\Fake\TheReplacer', 26 | 'MrClean\Test\Fake\TheWrapper', 27 | ]); 28 | 29 | $result = $this->cleaner->scrubbers(['the_replacer', 'the_wrapper']) 30 | ->scrub('This is just full of some esses.'); 31 | 32 | $this->assertSame('!Thim im jumt full of mome emmem.!', $result); 33 | } 34 | 35 | /** @test */ 36 | 37 | public function it_can_overwrite_a_default_scrubber() 38 | { 39 | $this->assertTrue(class_exists('MrClean\Scrubber\Boolean')); 40 | 41 | $this->cleaner->register([ 42 | 'MrClean\Test\Fake\Boolean', 43 | ]); 44 | 45 | $result = $this->cleaner->scrubbers(['boolean']) 46 | ->scrub('This is just full of some esses.'); 47 | 48 | $this->assertSame('booleaned!', $result); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /tests/BooleanTest.php: -------------------------------------------------------------------------------- 1 | cleaner->scrubbers(['boolean']) 13 | ->scrub(0); 14 | 15 | $this->assertSame(false, $result); 16 | } 17 | 18 | /** @test */ 19 | 20 | public function it_will_convert_an_empty_string_to_a_false() 21 | { 22 | $result = $this->cleaner->scrubbers(['boolean']) 23 | ->scrub(''); 24 | 25 | $this->assertSame(false, $result); 26 | } 27 | 28 | /** @test */ 29 | 30 | public function it_will_convert_a_whitespace_string_to_a_false() 31 | { 32 | $result = $this->cleaner->scrubbers(['boolean']) 33 | ->scrub(' '); 34 | 35 | $this->assertSame(false, $result); 36 | } 37 | 38 | /** @test */ 39 | 40 | public function it_will_convert_a_no_to_a_false() 41 | { 42 | $result = $this->cleaner->scrubbers(['boolean']) 43 | ->scrub('no'); 44 | 45 | $this->assertSame(false, $result); 46 | } 47 | 48 | /** @test */ 49 | 50 | public function it_will_convert_an_n_to_a_false() 51 | { 52 | $result = $this->cleaner->scrubbers(['boolean']) 53 | ->scrub('n'); 54 | 55 | $this->assertSame(false, $result); 56 | } 57 | 58 | /** @test */ 59 | 60 | public function it_will_convert_an_false_to_a_false() 61 | { 62 | $result = $this->cleaner->scrubbers(['boolean']) 63 | ->scrub('false'); 64 | 65 | $this->assertSame(false, $result); 66 | } 67 | 68 | /** @test */ 69 | 70 | public function it_will_convert_anything_else_to_a_true() 71 | { 72 | $result = $this->cleaner->scrubbers(['boolean']) 73 | ->scrub('cool'); 74 | 75 | $this->assertSame(true, $result); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/MrClean.php: -------------------------------------------------------------------------------- 1 | pre, $this->scrubbers, $this->post); 55 | $sanitizer = new Sanitizer($current, $this->registered); 56 | 57 | return $sanitizer->sanitize($dirty); 58 | } 59 | 60 | /** 61 | * Register class(es) as a cleaner 62 | * 63 | * @param string|array $classes 64 | */ 65 | 66 | public function register($classes) 67 | { 68 | if (!is_array($classes)) $classes = [$classes]; 69 | 70 | foreach ($classes as $class) { 71 | $short_name = basename(str_replace('\\', '/', $class)); 72 | $this->registered[$short_name] = $class; 73 | } 74 | } 75 | 76 | public function __call($requested_method, $arguments) 77 | { 78 | if (in_array($requested_method, ['pre', 'post', 'scrubbers'])) 79 | { 80 | $this->$requested_method = reset( $arguments ); 81 | 82 | return $this; 83 | } 84 | 85 | throw new \BadMethodCallException("Unknown method [{$requested_method}] called."); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/Scrubber/Html.php: -------------------------------------------------------------------------------- 1 | [\s]*<\/\1>/' => '', // empty tags (no content) 41 | '/<(.*)>[\s]*<\1>/' => '<$1>', // repeated opening tags 42 | '/<\/(.*)>[\s]*<\/\1>/' => '$1>', // repeated ending tags 43 | ]; 44 | 45 | /** 46 | * Clean up the html 47 | * 48 | * @return boolean 49 | */ 50 | 51 | public function scrub() 52 | { 53 | $this->stripTags(); 54 | $this->removeGarbage(); 55 | 56 | return $this->value; 57 | } 58 | 59 | /** 60 | * Strip the value of any tags not on the whitelist 61 | */ 62 | 63 | protected function stripTags() 64 | { 65 | $this->value = strip_tags($this->value, $this->whitelist()); 66 | } 67 | 68 | /** 69 | * Remove any bad syntax or empty elements 70 | */ 71 | 72 | protected function removeGarbage() 73 | { 74 | $search = array_keys($this->replace); 75 | $replace = array_values($this->replace); 76 | $this->value = preg_replace($search, $replace, $this->value); 77 | } 78 | 79 | /** 80 | * Compile the whitelist as a string full of tags 81 | * 82 | * @return string 83 | */ 84 | 85 | protected function whitelist() 86 | { 87 | $tags = array_map([$this, 'toTag'], $this->whitelist); 88 | 89 | return implode('', $tags); 90 | } 91 | 92 | /** 93 | * Tagify the string (i.e. wrap it in gt and lt) 94 | * 95 | * @param string $tag 96 | * @return string 97 | */ 98 | 99 | protected function toTag($tag) 100 | { 101 | return "<{$tag}>"; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /tests/CleanKeysTest.php: -------------------------------------------------------------------------------- 1 | cleaner->scrubbers(['name' => ['trim']]) 13 | ->scrub([ 14 | 'name' => ' Joe', 15 | 'job' => ' Developer' 16 | ]); 17 | 18 | $scrubbed = [ 19 | 'name' => 'Joe', 20 | 'job' => ' Developer' 21 | ]; 22 | 23 | $this->assertSame($scrubbed, $result); 24 | } 25 | 26 | /** @test */ 27 | 28 | public function it_can_clean_several_keys() 29 | { 30 | $result = $this->cleaner->scrubbers([ 31 | 'name' => ['trim'], 32 | 'job' => ['htmlentities'], 33 | ]) 34 | ->scrub([ 35 | 'name' => ' Joe', 36 | 'job' => ' Developer & Such' 37 | ]); 38 | 39 | $scrubbed = [ 40 | 'name' => 'Joe', 41 | 'job' => ' Developer & Such' 42 | ]; 43 | 44 | $this->assertSame($scrubbed, $result); 45 | } 46 | 47 | /** @test */ 48 | 49 | public function it_can_clean_several_keys_in_an_object() 50 | { 51 | $result = $this->cleaner->scrubbers([ 52 | 'name' => ['trim'], 53 | 'job' => ['htmlentities'], 54 | ]) 55 | ->scrub((object) [ 56 | 'name' => ' Joe', 57 | 'job' => ' Developer & Such' 58 | ]); 59 | 60 | $scrubbed = (object) [ 61 | 'name' => 'Joe', 62 | 'job' => ' Developer & Such' 63 | ]; 64 | 65 | $this->assertEquals($scrubbed, $result); 66 | } 67 | 68 | /** @test */ 69 | 70 | public function it_can_run_cleaners_on_all_and_specific_keys() 71 | { 72 | $result = $this->cleaner->scrubbers([ 73 | 'strip_tags', 74 | 'name' => ['trim'], 75 | 'job' => ['htmlentities'], 76 | ]) 77 | ->scrub([ 78 | 'name' => ' Joe', 79 | 'job' => ' Developer & Such' 80 | ]); 81 | 82 | $scrubbed = [ 83 | 'name' => 'Joe', 84 | 'job' => ' Developer & Such' 85 | ]; 86 | 87 | $this->assertSame($scrubbed, $result); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /tests/MrCleanTest.php: -------------------------------------------------------------------------------- 1 | cleaner->scrubbers(['trim']) 13 | ->scrub(' What is the deal'); 14 | 15 | $this->assertEquals('What is the deal', $result); 16 | } 17 | 18 | /** @test */ 19 | 20 | public function it_can_use_a_function_to_clean_an_array() 21 | { 22 | $result = $this->cleaner->scrubbers(['trim']) 23 | ->scrub([' What is the deal', 'How is it going? ']); 24 | 25 | $this->assertEquals(['What is the deal', 'How is it going?'], $result); 26 | } 27 | 28 | /** @test */ 29 | 30 | public function it_can_use_multiple_functions_to_clean_an_array() 31 | { 32 | $result = $this->cleaner->scrubbers(['htmlentities', 'trim']) 33 | ->scrub(['This & That ', ' How is it going?']); 34 | 35 | $this->assertEquals(['This & That', 'How is it going?'], $result); 36 | } 37 | 38 | /** @test */ 39 | 40 | public function it_can_use_a_function_to_clean_an_array_of_arrays() 41 | { 42 | $result = $this->cleaner->scrubbers(['trim']) 43 | ->scrub([ 44 | [' What is the deal', ' How is it going?'], 45 | [' Who is that?', ' What is up?'], 46 | ]); 47 | $scrubbed = [ 48 | ['What is the deal', 'How is it going?'], 49 | ['Who is that?', 'What is up?'], 50 | ]; 51 | 52 | $this->assertEquals($scrubbed, $result); 53 | } 54 | 55 | /** @test */ 56 | 57 | public function it_can_use_a_function_to_clean_an_array_of_objects() 58 | { 59 | $result = $this->cleaner->scrubbers(['trim']) 60 | ->scrub([ 61 | (object) ['greeting' => 'How is it going?'], 62 | (object) ['greeting' => 'What is up?'], 63 | ]); 64 | $scrubbed = [ 65 | (object) ['greeting' => 'How is it going?'], 66 | (object) ['greeting' => 'What is up?'], 67 | ]; 68 | 69 | $this->assertEquals($scrubbed, $result); 70 | } 71 | 72 | /** @test */ 73 | 74 | public function it_can_clean_a_nested_array_of_arrays_with_a_function() 75 | { 76 | $result = $this->cleaner->scrubbers(['trim']) 77 | ->scrub([ 78 | [ 79 | [' What is the deal', ' How is it going?'] 80 | ], 81 | [ 82 | [' Who is that?', ' What is up?'] 83 | ], 84 | ]); 85 | $scrubbed = [ 86 | [ 87 | ['What is the deal', 'How is it going?'] 88 | ], 89 | [ 90 | ['Who is that?', 'What is up?'] 91 | ], 92 | ]; 93 | 94 | $this->assertEquals($scrubbed, $result); 95 | } 96 | 97 | /** @test */ 98 | 99 | public function it_can_utilize_pre_and_post_cleaners() 100 | { 101 | $this->cleaner->pre(['trim']); 102 | $this->cleaner->post(['htmlentities']); 103 | 104 | $result = $this->cleaner->scrubbers(['strip_tags'])->scrub(' Hey, look at this & that.'); 105 | 106 | $this->assertSame('Hey, look at this & that.', $result); 107 | } 108 | 109 | /** @test */ 110 | 111 | public function it_can_clean_a_nested_array_of_mixed_types_with_a_function() 112 | { 113 | $result = $this->cleaner->scrubbers(['trim']) 114 | ->scrub([ 115 | [ 116 | (object) [ 117 | 'greetings' => [' What is the deal', ' How is it going?'] 118 | ], 119 | ], 120 | [ 121 | (object) [ 122 | 'greetings' => [' Who is that?', ' What is up?'] 123 | ], 124 | ], 125 | ]); 126 | $scrubbed = [ 127 | [ 128 | (object) [ 129 | 'greetings' => ['What is the deal', 'How is it going?'] 130 | ] 131 | ], 132 | [ 133 | (object) [ 134 | 'greetings' => ['Who is that?', 'What is up?'] 135 | ] 136 | ], 137 | ]; 138 | 139 | $this->assertEquals($scrubbed, $result); 140 | } 141 | 142 | /** @test */ 143 | 144 | public function it_alerts_the_user_when_they_call_a_non_existent_method() 145 | { 146 | $this->setExpectedException('BadMethodCallException'); 147 | 148 | $this->cleaner->somethingThatDoesntExist(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/Sanitizer.php: -------------------------------------------------------------------------------- 1 | scrubbers = $scrubbers; 26 | $this->registered = $registered; 27 | } 28 | 29 | /** 30 | * Router to correct type of sanitization 31 | * 32 | * @param array|object|string $dirty 33 | * @return array|object|string 34 | */ 35 | 36 | public function sanitize($dirty, $key = null) 37 | { 38 | if (is_object($dirty)) { 39 | return $this->sanitizeObject($dirty); 40 | } elseif (is_array($dirty)) { 41 | return $this->sanitizeArray($dirty); 42 | } else { 43 | return $this->sanitizeString($dirty, $key); 44 | } 45 | } 46 | 47 | /** 48 | * Clean a basic array 49 | * 50 | * @param array $array 51 | * @return array 52 | */ 53 | 54 | protected function sanitizeArray($array) 55 | { 56 | foreach ($array as $key => $value) { 57 | $array[$key] = $this->sanitize($value, $key); 58 | } 59 | 60 | return $array; 61 | } 62 | 63 | /** 64 | * Clean an object 65 | * 66 | * @param object $object 67 | * @return object 68 | */ 69 | 70 | protected function sanitizeObject($object) 71 | { 72 | foreach ($object as $key => $value) { 73 | $object->$key = $this->sanitize($value, $key); 74 | } 75 | 76 | return $object; 77 | } 78 | 79 | /** 80 | * Sanitize the string with the current set of scrubbers 81 | * 82 | * @param string $value 83 | * @param string|null $key 84 | * @return string 85 | */ 86 | 87 | protected function sanitizeString($value, $key) 88 | { 89 | return $this->runScrubbers($value, $this->scrubbers, $key); 90 | } 91 | 92 | /** 93 | * Run the array of scrubbers on the value, with an optional key to compare against 94 | * 95 | * @param string $value 96 | * @param array $scrubbers 97 | * @param string $key 98 | * @return string 99 | */ 100 | 101 | protected function runScrubbers($value, $scrubbers, $key = null) 102 | { 103 | foreach ($scrubbers as $scrubber_key => $scrubber) { 104 | // Do we have an array of scrubbers for a specific key? 105 | if (is_array($scrubber)) { 106 | if ($scrubber_key != $key) { 107 | // If it's not for this key, keep on moving 108 | continue; 109 | } 110 | 111 | return $this->runScrubbers($value, $scrubber); 112 | } 113 | 114 | if ($this->isScrubberClass($scrubber)) { 115 | $value = $this->getScrubber($scrubber, $value)->scrub(); 116 | } elseif (function_exists($scrubber)) { 117 | $value = $scrubber($value); 118 | } 119 | } 120 | 121 | return $value; 122 | } 123 | 124 | /** 125 | * Determines if cleaner is a valid Scrubber 126 | * 127 | * @param string $scrubber 128 | * @return boolean 129 | */ 130 | 131 | protected function isScrubberClass($scrubber) 132 | { 133 | if ($this->isRegistered($scrubber)) { 134 | return true; 135 | } 136 | 137 | return class_exists($this->getScrubberClassName($scrubber)); 138 | } 139 | 140 | /** 141 | * Check to see if this is a registered cleaner 142 | * 143 | * @param string $scrubber 144 | * @return boolean 145 | */ 146 | 147 | protected function isRegistered($scrubber) 148 | { 149 | $class = $this->getScrubberShortClassName($scrubber); 150 | 151 | return array_key_exists($class, $this->registered); 152 | } 153 | 154 | /** 155 | * Get the registered cleaner class name 156 | * 157 | * @param string $scrubber 158 | * @return string 159 | */ 160 | 161 | protected function getRegisteredClassName($scrubber) 162 | { 163 | $class = $this->getScrubberShortClassName($scrubber); 164 | 165 | return $this->registered[$class]; 166 | } 167 | 168 | /** 169 | * Get an instance of the specified Scrubber class 170 | * 171 | * @param string $scrubber 172 | * @param string $value 173 | * @return \MrClean\Scrubber 174 | */ 175 | 176 | protected function getScrubber($scrubber, $value) 177 | { 178 | if ($this->isRegistered($scrubber)) { 179 | $class = $this->getRegisteredClassName($scrubber); 180 | } else { 181 | $class = $this->getScrubberClassName($scrubber); 182 | } 183 | 184 | return new $class($value); 185 | } 186 | 187 | /** 188 | * Get just the base name for the Scrubber class 189 | * 190 | * @param string $scrubber 191 | * @return string 192 | */ 193 | 194 | protected function getScrubberShortClassName($scrubber) 195 | { 196 | $scrubber = str_replace(['-', '_'], ' ', $scrubber); 197 | $scrubber = ucwords($scrubber); 198 | 199 | return str_replace(' ', '', $scrubber); 200 | } 201 | 202 | /** 203 | * Get the full class path for the Scrubber 204 | * 205 | * @param string $scrubber 206 | * @return string 207 | */ 208 | 209 | protected function getScrubberClassName($scrubber) 210 | { 211 | 212 | return 'MrClean\Scrubber\\' . $this->getScrubberShortClassName($scrubber); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mr. Clean 2 | 3 | [](https://github.com/joetannenbaum/mr-clean/releases) 4 | [](LICENSE.md) 5 | [](https://travis-ci.org/joetannenbaum/mr-clean) 6 | [](https://scrutinizer-ci.com/g/joetannenbaum/mr-clean/code-structure) 7 | [](https://scrutinizer-ci.com/g/joetannenbaum/mr-clean) 8 | [](https://packagist.org/packages/joetannenbaum/mr-clean) 9 | 10 | Mr. Clean is an extendible PHP cleaner that allows you to easily clean up strings, arrays, objects, and anything in between. 11 | 12 | ## Table of Contents 13 | 14 | + [Installation](#installation) 15 | + [Basic Usage](#basic-usage) 16 | + [Scrubbers](#scrubbers) 17 | + [Pre/Post](#prepost) 18 | + [What Can Be Cleaned](#what-can-be-cleaned) 19 | + [Cleaning Specific Keys](#cleaning-specific-keys) 20 | + [Available Scrubbers](#available-scrubbers) 21 | + [Boolean](#boolean) 22 | + [HTML](#html) 23 | + [Strip CSS Attributes](#strip-css-attributes) 24 | + [Nullify](#nullify) 25 | + [Null If Repeated](#null-if-repeated) 26 | + [Strip Phone Number](#strip-phone-number) 27 | + [Extending](#extending) 28 | + [Writing a Scrubber](#writing-a-scrubber) 29 | + [Registering a Scrubber](#registering-a-scrubber) 30 | 31 | ## Installation 32 | 33 | Using [composer](https://packagist.org/packages/joetannenbaum/mr-clean): 34 | 35 | ``` 36 | { 37 | "require": { 38 | "joetannenbaum/mr-clean": "~0.0" 39 | } 40 | } 41 | ``` 42 | 43 | ## Basic Usage 44 | 45 | Fire it up like so: 46 | 47 | ```php 48 | require_once 'vendor/autoload.php'; 49 | 50 | $cleaner = new MrClean\MrClean(); 51 | ``` 52 | 53 | ## Scrubbers 54 | 55 | Scrubbers are the classes and functions that actually do the work, and you can assign as many as you want to clean your object. 56 | 57 | ```php 58 | $scrubbers = [ 59 | 'trim', 60 | 'stripslashes', 61 | 'strip_tags', 62 | 'remove_weird_characters', 63 | ]; 64 | 65 | $scrubbed = $cleaner->scrubbers($scrubbers)->scrub('I\'m not that dirty.'); 66 | ``` 67 | 68 | Scrubbers should always be passed as an array, and will be run in the order that you specify. 69 | 70 | Any single argument string manipulation function can be used. To reference a class, simply convert the StudlyCase to snake_case. In the example above, `remove_weird_characters` refers to a (fictional) class named `RemoveWeirdCharacters`. 71 | 72 | ## Pre/Post 73 | 74 | To save some typing, you can set scrubbers to run every time before and after each cleaning: 75 | 76 | ```php 77 | $cleaner->pre(['trim']); 78 | $cleaner->post(['htmlentities']); 79 | 80 | // trim will run before each of these, htmlentities after each 81 | $cleaner->scrubbers(['strip_tags'])->scrub('This should be cleaned.') 82 | $cleaner->scrubbers(['remove_weird_characters'])->scrub('So should this.') 83 | ``` 84 | 85 | ## What Can Be Cleaned 86 | 87 | Better question: what can't? An array of arrays, a string, an array of objects, a single object, you try it, Mr. Clean will probably be able to clean it. All of the following will work: 88 | 89 | ```php 90 | $scrubbed = $cleaner->scrubbers(['trim'])->scrub('Holy string, Batman.'); 91 | 92 | $scrubbed = $cleaner->scrubbers(['trim'])->scrub(['Holy', 'array', 'Batman']); 93 | 94 | $scrubbed = $cleaner->scrubbers(['trim'])->scrub([ 95 | ['Holy', 'array', 'of', 'arrays', 'Batman'], 96 | ['Holy', 'array', 'of', 'arrays', 'Batman'], 97 | ]); 98 | 99 | $scrubbed = $cleaner->scrubbers(['trim'])->scrub((object) [ 100 | 'first_word' => 'Holy', 101 | 'second_word' => 'object', 102 | 'third_word' => 'Batman', 103 | ]); 104 | 105 | $scrubbed = $cleaner->scrubbers(['trim'])->scrub([ 106 | (object) [ 107 | 'first_word' => 'Holy', 108 | 'second_word' => 'array', 109 | 'third_word' => 'of', 110 | 'fourth_word' => 'objects', 111 | 'fifth_word' => 'Batman', 112 | ], 113 | (object) [ 114 | 'first_word' => 'Holy', 115 | 'second_word' => 'array', 116 | 'third_word' => 'of', 117 | 'fourth_word' => 'objects', 118 | 'fifth_word' => 'Batman', 119 | ], 120 | ]); 121 | 122 | $scrubbed = $cleaner->scrubbers(['trim'])->scrub([ 123 | (object) [ 124 | 'first_word' => 'Holy', 125 | 'second_word' => 'mixed', 126 | 'third_word' => ['bag', 'Batman'], 127 | ], 128 | ]); 129 | ``` 130 | 131 | ## Cleaning Specific Keys 132 | 133 | Sometimes you don't want to use the same scrubbers on every key in an object or associative array. No problem. Just let Mr. Clean know which ones to apply where and he'll take care of it: 134 | 135 | ```php 136 | $scrubbers = [ 137 | 'first_name' => ['trim'], 138 | 'last_name' => ['stripslashes', 'htmlentities'], 139 | ]; 140 | 141 | $data = [ 142 | [ 143 | 'first_name' => 'Joe ', 144 | 'last_name' => 'O\'Donnell', 145 | ], 146 | [ 147 | 'first_name' => ' Harold', 148 | 'last_name' => 'Frank & Beans', 149 | ], 150 | ]; 151 | 152 | $scrubbed = $cleaner->scrubbers($scrubbers)->scrub($data); 153 | 154 | /* 155 | [ 156 | [ 157 | 'first_name' => 'Joe', 158 | 'last_name' => "O'Donnell", 159 | ], 160 | [ 161 | 'first_name' => 'Harold', 162 | 'last_name' => 'Frank & Beans', 163 | ], 164 | ] 165 | */ 166 | ``` 167 | 168 | You can also still specify scrubbers that should run for everything: 169 | 170 | ```php 171 | $scrubbers = [ 172 | 'strip_tags', 173 | 'first_name' => ['trim'], 174 | 'last_name' => ['stripslashes', 'htmlentities'], 175 | 'htmlspecialchars', 176 | ]; 177 | ``` 178 | 179 | ## Available Scrubbers 180 | 181 | Mr. Clean comes with a bevy of pre-built scrubbers you can use: 182 | 183 | ### Boolean 184 | 185 | Converts falsey text and anything considered `empty` to `false`, otherwise returns `true`. Falsey text includes (not case sensitive): 186 | 187 | + no 188 | + n 189 | + false 190 | 191 | ```php 192 | $movies_seen = [ 193 | 'The Dark Knight' => 'y', 194 | 'The Green Lantern' => 'n', 195 | 'The Avengers' => 'yes', 196 | ]; 197 | 198 | $scrubbed = $cleaner->scrubbers(['boolean'])->scrub( $movies_seen ); 199 | 200 | /* 201 | [ 202 | 'The Dark Knight' => true, 203 | 'The Green Lantern' => false, 204 | 'The Avengers' => true, 205 | ]; 206 | */ 207 | ``` 208 | 209 | ### HTML 210 | 211 | Strips tags not on the whitelist, removes empty content tags, and repeated opening or closing tags. The whitelist includes: 212 | 213 | + a 214 | + p 215 | + div 216 | + strong 217 | + em 218 | + b 219 | + i 220 | + br 221 | + ul 222 | + ol 223 | + li 224 | + h1 225 | + h2 226 | + h3 227 | + h4 228 | + h5 229 | + h6 230 | 231 | ```php 232 | $dirty = 'Some bad HTML here.
Some bad HTML here.
This was once bold.
'; 245 | 246 | $scrubbed = $cleaner->scrubbers(['strip_css_attributes'])->scrub($dirty); 247 | 248 | //This was once bold.
249 | ``` 250 | 251 | ### Nullify 252 | 253 | If a trimmed string doesn't have any length, null it out: 254 | 255 | ```php 256 | $dirty = [ 257 | 'cool', 258 | 'also cool', 259 | ' ', 260 | ' ', 261 | ]; 262 | 263 | $scrubbed = $cleaner->scrubbers(['nullify'])->scrub($dirty); 264 | 265 | /* 266 | [ 267 | 'cool', 268 | 'also cool', 269 | null, 270 | null, 271 | ]; 272 | */ 273 | ``` 274 | 275 | ### Null If Repeated 276 | 277 | If a string is just a repeated character ('1111111' or 'aaaaaaaaa') and has a length greater than two, null it out: 278 | 279 | ```php 280 | $dirty = [ 281 | '11111111', 282 | '22', 283 | 'bbbbbbbb', 284 | '333334', 285 | ]; 286 | 287 | $scrubbed = $cleaner->scrubbers(['null_if_repeated'])->scrub($dirty); 288 | 289 | /* 290 | [ 291 | null, 292 | '22', 293 | null, 294 | '333334', 295 | ]; 296 | */ 297 | ``` 298 | 299 | ### Strip Phone Number 300 | 301 | Strip a phone number down to just the good bits, numbers and the letter 'x' (for extensions): 302 | 303 | ```php 304 | $dirty = [ 305 | '555-555-5555', 306 | '(123) 456-7890', 307 | '198 765 4321 ext. 888', 308 | ]; 309 | 310 | $scrubbed = $cleaner->scrubbers(['strip_phone_number'])->scrub($dirty); 311 | 312 | /* 313 | [ 314 | '5555555555', 315 | '1234567890', 316 | '1987654321x888', 317 | ]; 318 | */ 319 | ``` 320 | 321 | ## Extending 322 | 323 | You can register custom scrubbers with Mr. Clean. 324 | 325 | ### Writing a Scrubber 326 | 327 | First, write your class. All you have to do is extend `MrClean\Scrubber\BaseScrubber` which adheres to `MrClean\Scrubber\ScrubberInterface`. There is a single property, `value` available to you. This is the string you will manipulate: 328 | 329 | ```php 330 | namespace Your\Namespace; 331 | 332 | use MrClean\Scrubber\BaseScrubber; 333 | 334 | class YourCustomScrubber extends BaseScrubber { 335 | 336 | public function scrub() 337 | { 338 | return str_replace('!', '.', $this->value); 339 | } 340 | 341 | } 342 | ``` 343 | 344 | And that's it. Now just register your scrubber with Mr. Clean. 345 | 346 | ### Registering a Scrubber 347 | 348 | The `register` method will take a string indicating the full path of the class, or an array of class paths. 349 | 350 | ```php 351 | $cleaner->register('Your\Namespace\YourCustomScrubber'); 352 | ``` 353 | 354 | Now, go ahead and use it: 355 | 356 | ```php 357 | $dirty = [ 358 | 'I need to calm down!', 359 | 'Me too!', 360 | ]; 361 | 362 | $scrubbed = $cleaner->scrubbers(['your_custom_scrubber'])->scrub($dirty); 363 | 364 | /* 365 | [ 366 | 'I need to calm down.', 367 | 'Me too.', 368 | ] 369 | */ 370 | ``` 371 | --------------------------------------------------------------------------------