├── README.md ├── config └── blacklist.php └── libraries └── Blacklist.php /README.md: -------------------------------------------------------------------------------- 1 | # Blacklist 2 | 3 | Version 1.0 4 | 5 | * Author: [Yang Hu](http://www.cnsaturn.com/), aka. Saturn 6 | 7 | Original thoughts borrowed from a framework called [egp](http://code.google.com/p/egp/) . 8 | 9 | ## DESCRIPTION 10 | 11 | This is a simple blacklist library written for CodeIgniter 1.7.x and the to-be-released CI 2.0. 12 | 13 | If you are googling a solution ONLY for preventing your app from spam blood, I STRONGLY recommend you using Wordpress Akismet service instead of this library. However, if you'd like to take full control of your blacklist dictionary, i.e., your application requires Internet censorship capabilities, you can consider this library. 14 | 15 | ## FEATURES 16 | 17 | 1. IP-address filtering. 18 | 2. Keyword-based string filtering 19 | 3. Regex-based string filtering 20 | 21 | ## INSTALLATION 22 | 23 | #### CodeIgniter 24 | 25 | 1. Put Blacklist.php into your application/libraries folder 26 | 2. Put blacklist.php into your application/config folder 27 | 3. Load it like normal: $this->load->library('blacklist'); OR you can autoload it. 28 | 29 | #### For other framework or app 30 | 31 | Dive into the code, you can find that it can be easily migrated to other apps without making hands dirty. 32 | 33 | ## Usage 34 | 35 | Check if the given text block contains forbidden keywords (return TRUE if it does exist, otherwise, return FALSE): 36 | 37 | $this->blacklist->check_text('I am a spammer!')->is_blocked(); 38 | 39 | Check if the client IP is blocked by the system (return TRUE if it is blocked) : 40 | 41 | $this->blacklist->check_ip('1.1.1.1')->is_blocked(); 42 | 43 | If a forbidden keyword (such as word 'spammer') was found in the given text block, we can do the following replacement: 44 | 45 | $this->blacklist->replace('I am a spammer!', '@'); 46 | 47 | After this, The original text will be turned into 'I am a @@@@@@@!' -------------------------------------------------------------------------------- /config/blacklist.php: -------------------------------------------------------------------------------- 1 | 11 | * @license Apache License v2.0 12 | * @copyright 2010 Yang Hu 13 | * 14 | * Licensed under the Apache License, Version 2.0 (the "License"); 15 | * you may not use this file except in compliance with the License. 16 | * You may obtain a copy of the License at 17 | * 18 | * http://www.apache.org/licenses/LICENSE-2.0 19 | * 20 | * Unless required by applicable law or agreed to in writing, software 21 | * distributed under the License is distributed on an "AS IS" BASIS, 22 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | * See the License for the specific language governing permissions and 24 | * limitations under the License. 25 | */ 26 | 27 | // Forbidden IP adresses 28 | $config['ip_addresses'] = array('10.55.66.*'); 29 | 30 | // Forbidden keywords 31 | $config['words'] = array('GFW', 'FUCK', '群体灭绝', '红色恐怖', '迷魂药', '代开发票'); 32 | 33 | // Regexs (aka. regular expression) patterns 34 | // It should be PERL style!! 35 | $config['regexs'] = array(); 36 | 37 | /* End of file blacklist.php */ 38 | /* Location: ./system/application/config/blacklist.php */ -------------------------------------------------------------------------------- /libraries/Blacklist.php: -------------------------------------------------------------------------------- 1 | 10 | * @license Apache License v2.0 11 | * @copyright 2010 Yang Hu 12 | * 13 | * Licensed under the Apache License, Version 2.0 (the "License"); 14 | * you may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at 16 | * 17 | * http://www.apache.org/licenses/LICENSE-2.0 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | */ 25 | class Blacklist 26 | { 27 | 28 | /** 29 | * Blocked ip addresses 30 | * 31 | * @access protected 32 | * @var array 33 | */ 34 | protected $_ip_addresses = array(); 35 | 36 | /** 37 | * Forbidden keywords 38 | * 39 | * @access protected 40 | * @var array 41 | */ 42 | protected $_words = array(); 43 | 44 | /** 45 | * Regexs that can be used to match against 46 | * special forbidden string pattern 47 | * 48 | * @access protected 49 | * @var array 50 | */ 51 | protected $_regexs = array(); 52 | 53 | /** 54 | * Is the target IP or text block permitted? 55 | * 56 | * @access protected 57 | * @var bool 58 | */ 59 | protected $_blocked = FALSE; 60 | 61 | /** 62 | * IP addresses to check 63 | * 64 | * @access public 65 | * @var array 66 | */ 67 | public $target_ip = array(); 68 | 69 | /** 70 | * Text blocks to check 71 | * 72 | * @access public 73 | * @var array 74 | */ 75 | public $target_text = array(); 76 | 77 | /** 78 | * Construct 79 | * 80 | * Populate our blacklist from the config file. 81 | * 82 | * 83 | * @access public 84 | * @param array $config 85 | * @var array 86 | */ 87 | public function __construct($config) 88 | { 89 | // Notice: Config array corresponding with the class are automatically 90 | // loaded when loading the library itself 91 | if (!empty($config)) 92 | { 93 | foreach ($config as $key => $val) 94 | { 95 | if (isset($this->{'_' . $key})) 96 | { 97 | $val = ! empty($val) ? is_array($val) ? $val : array($val) : array(); 98 | $this->{'_' . $key} = $val; 99 | } 100 | } 101 | } 102 | } 103 | 104 | // -------------------------------------------------------------------- 105 | 106 | /** 107 | * Is the target IP or text block blocked? 108 | * 109 | * @access public 110 | * @return bool TRUE if it is blocked 111 | */ 112 | public function is_blocked() 113 | { 114 | return $this->_blocked; 115 | } 116 | 117 | // -------------------------------------------------------------------- 118 | 119 | /** 120 | * Add an IP address to the current forbidden IP blacklist 121 | * 122 | * @access public 123 | * @param mixed array|string IP address or an array of addresses (allows wildcard '*') 124 | * @return object $this 125 | */ 126 | public function add_ip($ips) 127 | { 128 | $ips = ! is_array($ips) ? array($ips) : $ips; 129 | 130 | foreach($ips as $ip) 131 | { 132 | if (preg_match('/^([\d\*]{1,3}\.){3}[\d\*]{1,3}$/', $ip)) 133 | { 134 | $long = ip2long(str_replace('*', '1', $ip)); 135 | 136 | if ($long != -1 AND $long !== FALSE) 137 | { 138 | continue; 139 | } 140 | } 141 | 142 | show_error("Invalid IP address: $ip"); 143 | } 144 | 145 | $this->_ip_addresses = array_merge($this->_ip_addresses, $ips); 146 | 147 | return $this; 148 | } 149 | 150 | // -------------------------------------------------------------------- 151 | 152 | /** 153 | * Add a keyword to the current forbidden word blacklist 154 | * 155 | * @access public 156 | * @param mixed array|string keyword or an array of keywords 157 | * @return object $this 158 | */ 159 | public function add_word($words) 160 | { 161 | $words = ! is_array($words) ? array($words) : $words; 162 | 163 | $this->_words = array_merge($this->_words, $words); 164 | 165 | return $this; 166 | } 167 | 168 | // -------------------------------------------------------------------- 169 | 170 | /** 171 | * Add a regex (aka. regular expression) pattern to the blacklist 172 | * 173 | * @access public 174 | * @param mixed array|string regex or an array of regexs 175 | * @return object $this 176 | */ 177 | public function add_regex($regexs) 178 | { 179 | $regexs = ! is_array($regexs) ? array($regexs) : $regexs; 180 | 181 | $this->_regexs = array_merge($this->_regexs, $regexs); 182 | 183 | return $this; 184 | } 185 | 186 | // -------------------------------------------------------------------- 187 | 188 | 189 | /** 190 | * Check whether or not the IP is in the blacklist 191 | * 192 | * @access public 193 | * @return object $this 194 | */ 195 | public function check_ip($ips) 196 | { 197 | $this->_reset_block_status(); 198 | 199 | $this->_set_target_ip($ips); 200 | 201 | $ip_address = implode(" ", $this->target_ip); 202 | 203 | foreach ($this->_ip_addresses as $ip) 204 | { 205 | $regex = str_replace(array('*', '.'), array('\d{1,3}', '\.'), $ip); 206 | 207 | if (preg_match("/$regex/", $ip_address)) { 208 | 209 | $this->_blocked = TRUE; 210 | 211 | log_message('debug', "Found IP address in the blacklist: '$ip'"); 212 | } 213 | } 214 | 215 | return $this; 216 | } 217 | 218 | // -------------------------------------------------------------------- 219 | 220 | /** 221 | * Check whether or not the text block includes forbidden keywords 222 | * 223 | * @access public 224 | * @param string $texts text blocks to check 225 | * @return object $this 226 | */ 227 | public function check_text($texts) 228 | { 229 | $this->_reset_block_status(); 230 | 231 | $this->_set_target_text($texts); 232 | 233 | foreach ($this->_words as $word) 234 | { 235 | if (stripos($this->target_text, $word) !== FALSE) 236 | { 237 | $this->_blocked = TRUE; 238 | 239 | log_message('debug', "Found forbidden word: '$word' in the given text."); 240 | } 241 | } 242 | 243 | return $this; 244 | } 245 | 246 | // -------------------------------------------------------------------- 247 | 248 | /** 249 | * Check whether or not the given text includes strings that matching 250 | * the regex. 251 | * 252 | * @access public 253 | * @return object $this 254 | */ 255 | public function check_regex() 256 | { 257 | $this->_reset_block_status(); 258 | 259 | foreach ($this->_regexs as $regex) 260 | { 261 | if (preg_match($regex, $this->target_text, $m)) 262 | { 263 | $this->_blocked = TRUE; 264 | 265 | log_message('debug', "Found forbidden word '$word' in the text."); 266 | } 267 | } 268 | 269 | return $this; 270 | } 271 | 272 | // -------------------------------------------------------------------- 273 | 274 | /** 275 | * Replace the forbidden word(s) 276 | * 277 | * @access public 278 | * @param mixed array|string The given text block or an array of text blocks 279 | * @param string marks to replace the forbidden word(s) 280 | * @return mixed array|string 281 | */ 282 | public function replace($text, $fill = '*') 283 | { 284 | // If $text is an array, this function recursively invokes itself 285 | if (is_array($text) AND !empty($text)) 286 | { 287 | $result = array(); 288 | 289 | foreach ($text as $t) 290 | { 291 | $result[] = $this->replace($t, $fill); 292 | } 293 | 294 | return $result; 295 | } 296 | // If $text is just a string... 297 | else 298 | { 299 | // Replace the words matched aganist that within the blacklist 300 | foreach ($this->_words as $word) 301 | { 302 | if (stripos($text, $word) !== FALSE) 303 | { 304 | $replacement = implode('', array_fill(0, iconv_strlen($word, 'UTF-8'), $fill)); 305 | $result = str_ireplace($word, $replacement, $text); 306 | $text = $result; 307 | } 308 | } 309 | 310 | // Replace the regexs matched aganist that within the blacklist 311 | foreach ($this->_regexs as $regex) 312 | { 313 | if (preg_match($regex, $result)) 314 | { 315 | // Fill stuff for regexs are not that accurate because of escape marks, 316 | // so we only exclude the starting and ending mark of the regex, that is '/' 317 | // e.g. /\bphp\b/i 318 | $replacement = implode('', array_fill(0, iconv_strlen($regex, 'UTF-8') - 2, $fill)); 319 | $result = preg_replace($regex, $replacement, $result); 320 | } 321 | } 322 | 323 | return $result; 324 | } 325 | 326 | return; 327 | } 328 | 329 | // -------------------------------------------------------------------- 330 | 331 | /** 332 | * Set the target IP 333 | * 334 | * @access private 335 | * @param mixed array|string 336 | * @return object $this 337 | */ 338 | private function _set_target_ip($ips) 339 | { 340 | $ips = ! is_array($ips) ? array($ips) : $ips; 341 | 342 | foreach($ips as $ip) 343 | { 344 | if (preg_match('/^([\d\*]{1,3}\.){3}[\d\*]{1,3}$/', $ip)) 345 | { 346 | $long = ip2long(str_replace('*', '1', $ip)); 347 | 348 | if ($long != -1 AND $long !== FALSE) 349 | { 350 | continue; 351 | } 352 | } 353 | 354 | show_error(lang('invalid_ip', array($ip))); 355 | } 356 | 357 | $this->target_ip = $ips; 358 | } 359 | 360 | 361 | // -------------------------------------------------------------------- 362 | 363 | /** 364 | * Set the target text block 365 | * 366 | * @access private 367 | * @param mixed array|string 368 | * @return object $this 369 | */ 370 | private function _set_target_text($texts) 371 | { 372 | $texts = ! is_array($texts) ? array($texts) : $texts; 373 | 374 | $this->target_text = implode("\n", $texts); 375 | } 376 | 377 | // -------------------------------------------------------------------- 378 | 379 | /** 380 | * Reset block status 381 | * 382 | * @access private 383 | * @return object $this 384 | */ 385 | private function _reset_block_status() 386 | { 387 | $this->_blocked = FALSE; 388 | } 389 | 390 | } 391 | 392 | /* End of file Blacklist.php */ 393 | --------------------------------------------------------------------------------