Рейтинг@Mail.ru
 

Шаг 3

Непарные теги

Ну а теперь еще один излюбленный способ вандалов нагадить на не совсем хорошо реализованном сайте. Так называемые незакрытые теги. Дело в том, что если запостить такой текст:
[s]зачеркнуто
то зачеркнутым окажется не только это слово, но и все последующие. И не только в пределах поста, а и на всем остальном сайте.

По этому нужно как то от этого обезопаситься. Есть много способов - разбирать текст посимвольно и считать открытые и закрытые теги, метод конечных автоматов, замена регулярками только парных тегов и еще несколько. Все они имеют недостатки. Самый большой, который присущь почти всем методам, это еще один побочный эфект bb-разметки. Дело в том, что тег состоит из нескольких символов. И функция wordwrap() или наша mBwordwrap() может запросто разорвать тег, если разрыв придется на его середину. Можете убедиться, запостив в тестовй скрипт этот текст:
[b]м[/b][b]н[/b][b]о[/b][b]г[/b][b]о[/b][i]т[/i][i]е[/i][i]г[/i][i]о[/i][i]в[/i][u]п[/u][u]о[/u][u]д[/u][u]р[/u][u]я[/u][u]д[/u][b]м[/b][b]н[/b][b]о[/b][b]г[/b][b]о[/b][i]т[/i][i]е[/i][i] г[/i][i]о[/i][i]в[/i][u]п[/u][u]о[/u][u]д[/u][u]р[/u][u]я[/u][u]д[/u]


Разрыв придется как раз на тег и все испортится.

Мы попытаемся решить эти все проблемы нетрадиционным и весьма оригинальным способом. Перед обработками заменим все теги на так называемые токены. Смысл этой операции прост - теги из многосимвольных комбинаций превратим в односимвольные. А их и легче считать, и разорвать невозможно.

Вот тут еще один момент - не зря мы делаем все в UTF-8. Если кто то попытается использовать этот скрипт под другой местечковой кодировкой - ничего не выйдет. Мы предупреждали - привыкайте к хорошему. Дело в том, что в качестве токенов мы будем использовать редко применяемые, многобайтные символы. Их там полно.

Но для начала нужно немного исправить скрипт, чтобы можно было вынести все настройки в конфигурационный файл.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php

/**
* Конфигурационный файл интерпретатора BB-тегов
*/
/////////////////////////////////////////////////////////////////////////


    // Путь до корня скрипта
    
define('IRB_BB_PATH''http://'$_SERVER['HTTP_HOST']); 

    
$configBBcode = array(
                                                                                      
            
// Парные BB-теги
             
'setup_bb'    => array(
                                       
'[b]'                =>   '[/b]',
                                       
'[i]'                =>   '[/i]',
                                       
'[s]'                =>   '[/s]',
                                       
'[u]'                =>   '[/u]',                                      

                                    ),
                                                 
             
// Парные HTML-теги (на них заменяются теги из предыдущего массива)                     
             
'setup_html'  => array(
                                       
'<b>'                =>   '</b>',
                                       
'<i>'                =>   '</i>',
                                       
'<s>'                =>   '</s>',
                                       
'<u>'                =>   '</u>',
                                   ), 
         
                                                                   
             
// Не парные теги (смайлики и иже с ними)                       
             
'single_tags' => array(
                                      
'[:)]'     =>   '<img src="'IRB_BB_PATH .'/smiles/1.gif" />',
                                      
'[:(]'     =>   '<img src="'IRB_BB_PATH .'/smiles/2.gif" />',
                                      
'[;)]'     =>   '<img src="'IRB_BB_PATH .'/smiles/3.gif" />',
                                      
'[:D]'     =>   '<img src="'IRB_BB_PATH .'/smiles/4.gif" />',
                                   ),
                                                     
                      );


Для удобства работы с конфигурационными данными, поместим их в один массив. Это пригодится, когда будем делать форматтеры. Ну и элементы расположим поудобнее. Открывающий - закрывающий. Все на виду. Можно спокойно добавлять новые пары тегов, главное сохранять последовательность.
Заодно сразу пропишем пути до самйликов, чтобы не искать потом вчерашний день.

А теперь переделаем и саму функцию в свете вновь открывшихся обстоятельств.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php

// Конфига
    
include './config.php';

/**   
* Основная функция интерпретатора
* @param string $text   //обрабатываемый текст
* @return string 
*/   
    
function createBBtags($text
    {   
// Разбираем конфигурционный массив в текущую таблицу переменных
        
global $configBBcode;
        
extract($configBBcode);
// Разбираем полученные массивы на массивы элементов            
        
$bb_open      array_keys($setup_bb);
        
$bb_close     array_values($setup_bb);                                                        
        
$html_open    array_keys($setup_html);
        
$html_close   array_values($setup_html);
        
$bb_single    array_keys($single_tags);
        
$html_single  array_values($single_tags);
// Обрабатываем текст            
        
$text str_replace("\r"""$text);
        
$text str_replace("\t""    "$text);
        
$text mBwordwrap($text100);                 
        
$text htmlspecialchars($text);
/** 
Заменяем bb-теги на HTML. 
Используется функция str_ireplace(), чтобы BB-теги были регистронезависимыми
*/                       
        
$text str_ireplace($bb_open$html_open$text);
        
$text str_ireplace($bb_close$html_close$text);
        
$text str_ireplace($bb_single$html_single$text);
// Сохраняем оригинальное форматирование                
        
$text str_replace('  ''&nbsp;&nbsp;'$text);    
        
$text nl2br($text);
// За ушкО на солнышкО                       
        
return $text;            
    }

Тут нужно обратить внимание на функцию extract() Эта функция разбирает массив в текущую таблицу переменных. Что это значит. Это значит, что после обработки такого массива
1
2
3
4
5
6
7
8
9
<?php

    $arr 
= array( 
                   
'var1' => 'Значение1',
                   
'var2' => 'Значение2',
                );
    
extract($arr);

В скрипте появятся переменные $var1 и $var2

То есть верхняя запись идентична такой:
1
2
3
4
5
6
<?php

    $var1 
'Значение1';
    
$var2 'Значение2';
а значит в нашей функции теперь есть переменные с массивами из конфиги.

Можно заменить функцию в тестовом скрипте и посмотреть - все прекрасно работает.

Вот а теперь собственно начинаются сами телодвижения, ради которых все это и подготавливалось. Для начала добавим в конфигу массивы так называемых токенов. Сразу с запасом, чтобы bb-тегов можно было использовать много:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php


/**
* Конфигурационный файл интерпретатора BB-тегов
*/
/////////////////////////////////////////////////////////////////////////


    // Путь до корня скрипта
    
define('IRB_BB_PATH''http://'$_SERVER['HTTP_HOST'] .'/bbcode'); 

    
$configBBcode = array(
                                                                                      
            
// Парные BB-теги
             
'setup_bb'    => array(
                                       
'[b]'                =>   '[/b]',
                                       
'[i]'                =>   '[/i]',
                                       
'[s]'                =>   '[/s]',
                                       
'[u]'                =>   '[/u]',                                      

                                    ),
                                                 
             
// Парные HTML-теги (на них заменяются теги из предыдущего массива)                     
             
'setup_html'  => array(
                                       
'<b>'                =>   '</b>',
                                       
'<i>'                =>   '</i>',
                                       
'<s>'                =>   '</s>',
                                       
'<u>'                =>   '</u>',
                                   ), 
         
                                                                   
             
// Не парные теги (смайлики и иже с ними)                       
             
'single_tags' => array(
                                      
'[:)]'     =>   '<img src="'IRB_BB_PATH .'/smiles/1.gif" />',
                                      
'[:(]'     =>   '<img src="'IRB_BB_PATH .'/smiles/2.gif" />',
                                      
'[;)]'     =>   '<img src="'IRB_BB_PATH .'/smiles/3.gif" />',
                                      
'[:D]'     =>   '<img src="'IRB_BB_PATH .'/smiles/4.gif" />',
                                   ),
                                                     
/** 
Массивы символов замены. Для корректной обработки теги нужно заменить на
одиночные символы, иначе можно порвать тег. Количество символов должно соответствовать количеству тегов.
Используются редко используемые символы 
*/
    
        // Открывающие теги
                
'tmp_open'   => array(
                                       
'ᐁ''ᐂ''ᐃ''ᐄ''ᐅ''ᐆ''ᐇ''ᐉ''ᐊ''ᐋ'
                                       
'ᐌ''ᐍ''ᐎ''ᐏ''ᐐ''ᐑ''ᐒ''ᐓ''ᐔ''ᐕ'
                                       
'ᐫ''ᐬ''ᐭ''ᐮ''ᐯ''ᐰ''ᐱ''ᐲ''ᐳ''ᐴ'
                                       
'ᐵ''ᐷ''ᐸ''ᐹ''ᐺ''ᐻ''ᐼ''ᐽ''ᐾ''ᐿ'
                                       
'ᑌ''ᑍ''ᑎ''ᑏ''ᑐ''ᑑ''ᑒ''ᑔ''ᑕ''ᑖ',

                                    ),                              
                           
        
// Закрывающие теги                  
                
'tmp_close'  => array(
                                        
                                       
'ᑗ''ᑘ''ᑙ''ᑚ''ᑛ''ᑜ''ᑝ''ᑞ''ᑟ''ᑠ',  
                                       
'ᑡ''ᑢ''ᑣ''ᑤ''ᑥ''ᑧ''ᑨ''ᑩ''ᑪ''ᑫ',
                                       
'ᑬ''ᑭ''ᑮ''ᑯ''ᑰ''ᑱ''ᑲ''ᑳ''ᑴ''ᑵ'
                                       
'ᑶ''ᑷ''ᑸ''ᑹ''ᑺ''ᑻ''ᑼ''ᑽ''ᑾ''ᑿ'
                                       
'ᒀ''ᒁ''ᒂ''ᒌ''ᒍ''ᒎ''ᒏ''ᒐ''ᒑ''ᒒ',

                                    ),                            
        
// Одиночные теги                                  
                
'tmp_single' => array(                  
                                       
'ᒓ''ᒔ''ᒕ''ᒖ''ᒗ''ᒘ''ᒙ''ᒚ''ᒛ''ᒜ'
                                       
'ᒝ''ᒞ''ᒟ''ᒠ''ᒣ''ᒤ''ᒥ''ᒦ''ᒧ''ᒨ'
                                       
'ᒩ''ᒪ''ᒫ''ᒬ''ᒭ''ᒮ''ᒯ''ᒰ''ᒱ''ᒲ'
                                       
'ᒳ''ᒴ''ᒵ''ᒶ''ᒷ''ᒸ''ᒹ''ᒺ''ᓀ''ᓁ'
                                       
'ᓂ''ᓃ''ᓄ''ᓅ''ᓆ''ᓇ''ᓈ''ᓉ''ᓊ''ᓋ'
                                    ),
                     );


Теперь в начале обработки заменим bb-теги на эти символы, обработаем текст и заменим временные символы на HTML теги.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php

// Конфига
    
include './config.php';

/**   
* Основная функция интерпретатора
* @param string $text   //обрабатываемый текст
* @return string 
*/   
    
function createBBtags($text
    {   
// Разбираем конфигурционный массив в текущую таблицу переменных
        
global $configBBcode;
        
extract($configBBcode);
// Разбираем полученные массивы на массивы элементов            
        
$bb_open      array_keys($setup_bb);
        
$bb_close     array_values($setup_bb);                                                        
        
$html_open    array_keys($setup_html);
        
$html_close   array_values($setup_html);
        
$bb_single    array_keys($single_tags);
        
$html_single  array_values($single_tags);
            
        
$text str_replace("\r"""$text);
        
$text str_replace("\t""    "$text);
/** 
Заменяем bb-теги на токены. 
Используется функция str_ireplace(), чтобы BB-теги были регистронезависимыми
*/                       
        
$text str_ireplace($bb_open$tmp_open$text);
        
$text str_ireplace($bb_close$tmp_close$text);
        
$text str_ireplace($bb_single$tmp_single$text);
                
// Обрабатываем текст        
        
$text mBwordwrap($text100);                 
        
$text htmlspecialchars($text);
/** 
Все готово. 
Меняем временные символы на HTML теги
*/    
        
$text str_replace($tmp_open$html_open$text);
        
$text str_replace($tmp_close$html_close$text);
        
$text str_replace($tmp_single$html_single$text);
        
// Сохраняем оригинальное форматирование                
        
$text str_replace('  ''&nbsp;&nbsp;'$text);    
        
$text nl2br($text);
// За ушкО на солнышкО                       
        
return $text;            
    } 


Больше тег рваться не будет, можете убедиться.
Однако из такой схемы можно извлечь еще одну немаловажную пользу - удалить пустые теги, чтобы не мусорили где попало. А так же удалить непарные, чтобы уберечься от вандалов.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

/** 
Начинается разбор полетов. Сначала уничтожаем пустые теги.
Тут же за одно считаем, сколько открывающих и сколько закрывающих
*/ 
        
$open_cnt = array();
   
        foreach(
$tmp_open as $k => $v)
        {
           
$text preg_replace("#"$v ."\s*?"$tmp_close[$k] ."#us"""$text);
           
$cnt substr_count($text$v);
           
           if(
$cnt 0)
           {
               
$open_cnt[$v] = $cnt;
               
$close_cnt[$v] = substr_count($text$tmp_close[$k]);
           }              
        }
        
/** 
Дальше уничтожаем непарные теги
Регулярка составлена так, что удаляет последний заявленный символ
Это дает возможность удалить незакрытые теги с конца текста,
не трогая закрытые.
*/     
        
foreach($open_cnt as $k => $v)
        {
                
            if(
$v $close_cnt[$k])
            {
                for(
$i 0$i $v $close_cnt[$k]; ++$i)
                    
$text preg_replace('#'$k .'(?!.*'$k .')#us'''$text);
            }
        
        }


Тут мы проходимся циклом по массиву с токенами открывающих тегов (они для того и в разных массивах) и смотрим, есть ли между ним и соответствующим закрывающим тегом какие то символы, отличные от пробела. Если нету - удаляем эту пару из текста. За одно считаем, сколько открывающих и сколько закрывающих тегов.
В следующем цикле мы проходим по выше подготовленному массиву и уничтожаем незакрытые теги. Регулярка составлена таким образом, что удаляться будут открывающие теги по одному за виток, начиная с конца. Тоесть если на входе такой текст:
1
2
[b][/b][b][b]текст[/b]
то после обработки останется такой:
1
2
[b]текст[/b]
и действующая разметка не пострадает.

Поместим эти циклы в функцию и проверим:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?php

// Конфига
    
include './config.php';

/**   
* Основная функция интерпретатора
* @param string $text   //обрабатываемый текст
* @return string 
*/   
    
function createBBtags($text
    {   
// Разбираем конфигурционный массив в текущую таблицу переменных
        
global $configBBcode;
        
extract($configBBcode);
// Разбираем полученные массивы на массивы элементов            
        
$bb_open      array_keys($setup_bb);
        
$bb_close     array_values($setup_bb);                                                        
        
$html_open    array_keys($setup_html);
        
$html_close   array_values($setup_html);
        
$bb_single    array_keys($single_tags);
        
$html_single  array_values($single_tags);
            
        
$text str_replace("\r"""$text);
        
$text str_replace("\t""    "$text);
/** 
Заменяем bb-теги на токены. 
Используется функция str_ireplace(), чтобы BB-теги были регистронезависимыми
*/                       
        
$text str_ireplace($bb_open$tmp_open$text);
        
$text str_ireplace($bb_close$tmp_close$text);
        
$text str_ireplace($bb_single$tmp_single$text);
                

/** 
Начинается разбор полетов. Сначала уничтожаем пустые теги.
Тут же за одно считаем, сколько открывающих и сколько закрывающих
*/ 
        
$open_cnt = array();
   
        foreach(
$tmp_open as $k => $v)
        {
           
$text preg_replace("#"$v ."\s*?"$tmp_close[$k] ."#us"""$text);
           
$cnt substr_count($text$v);
           
           if(
$cnt 0)
           {
               
$open_cnt[$v] = $cnt;
               
$close_cnt[$v] = substr_count($text$tmp_close[$k]);
           }              
        }
        
/** 
Дальше уничтожаем непарные теги
Регулярка составлена так, что удаляет последний заявленный символ
Это дает возможность удалить незакрытые теги с конца текста,
не трогая закрытые.
*/     


        
foreach($open_cnt as $k => $v)
        {
                
            if(
$v $close_cnt[$k])
            {
                for(
$i 0$i $v $close_cnt[$k]; ++$i)
                    
$text preg_replace('#'$k .'(?!.*'$k .')#us'''$text);
            }
        
        }
                
// Обрабатываем текст        
        
$text mBwordwrap($text100);                 
        
$text htmlspecialchars($text);        
/** 
Все готово. 
Меняем обратно временные символы на HTML теги
*/    
        
$text str_replace($tmp_open$html_open$text);
        
$text str_replace($tmp_close$html_close$text);
        
$text str_replace($tmp_single$html_single$text);
        
// Сохраняем оригинальное форматирование                
        
$text str_replace('  ''&nbsp;&nbsp;'$text);    
        
$text nl2br($text);
// За ушкО на солнышкО                       
        
return $text;            
    }


Но пасраран! Как говорится. Вот теперь можно спать спокойно. Или почти спокойно. Есть еще одно побочное явление. Если запостить пустой тег, допустим [b][/b], то скрипт его зарежет. Но зарежет на выводе. А если этот текст попадет на вход, то запишется в базу. И получится пустой пост, чего нам тоже совсем не хочется. Что за молчанка? Взял слово - говори. )

По этому перед записью текста на носитель нужно проверить, есть ли полезный текст или опять кто то балуется. Можно сделать это отдельно, а можно заставить работать нашу функцию "наоборот". То есть чистить текст от любых BB-тегов. На подобие функции PHP strip_tags(). Это может быть полезно и в других местах, для организации так называемых превью. То есть первых нескольких предложений со ссылкой "читать дальше". Дело в том, что разрыв текста в превью может попасть между тегами и тогда наши поползновения будут напрасны. Самый простой способ борьбы с этим - удалить из превью все теги и не мучаться. А в полном тексте явить миру всю его красоту.

Итак, сделаем этот функционал, добавив в функцию еще один аргумент. Если в него передать false, то функция очистит текст от всех bb-тегов.
И еще, если какой то "умелец" прознает, как устроен этот скрипт, то обязательно начнет сувать в него всякие иероглифы. А значит все защиты от вандалов напрасны.
Чтобы предотвратить безобразие, нужно удалить из текста все служебные символы. Сделаем это простой заменой служебных символов. содержащихся в массивах, на пустоту.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php

// Конфига
    
include './config.php';

/**   
* Основная функция интерпретатора
* @param string $text   //обрабатываемый текст
* @return string 
*/   
    
function createBBtags($text$replace true)
    {   
// Разбираем конфигурционный массив в текущую таблицу переменных
        
global $configBBcode;
        
extract($configBBcode);
// Разбираем полученные массивы на массивы элементов            
        
$bb_open      array_keys($setup_bb);
        
$bb_close     array_values($setup_bb);                                                        
        
$html_open    array_keys($setup_html);
        
$html_close   array_values($setup_html);
        
$bb_single    array_keys($single_tags);
        
$html_single  array_values($single_tags);
        
    
//  Oчистим текст от иероглифов
        
$text str_replace($tmp_open''$text);
        
$text str_replace($tmp_close''$text);
        
$text str_replace($tmp_single''$text);
                  
        
$text str_replace("\r"""$text);
        
$text str_replace("\t""    "$text);
        
/** 
Если режим очистки - 
удаляем бб-теги из текста
*/                 
    
if(!$replace)
    {              
        
$text str_replace($bb_open''$text);
        
$text str_replace($bb_close''$text);
        
$text str_replace($bb_single''$text);
        
$text preg_replace('#\\[(code|url|img|video)[^\s]*?\].*?\[/\\1\]#usi'''$text);
    }
    else
    {        
/** 
Если включен режим bb-тегов, 
заменим заявленные теги на одиночные символы и дальше по тексту 
Используется функция str_ireplace(), чтобы BB-теги были регистронезависимыми
*/ 

                   
        
$text str_ireplace($bb_open$tmp_open$text);
        
$text str_ireplace($bb_close$tmp_close$text);
        
$text str_ireplace($bb_single$tmp_single$text);   
/** 
Начинается разбор полетов. Сначала уничтожаем пустые теги.
Тут же за одно считаем, сколько открывающих и сколько закрывающих
*/ 
        
$open_cnt = array();
   
        foreach(
$tmp_open as $k => $v)
        {
           
$text preg_replace("#"$v ."\s*?"$tmp_close[$k] ."#us"""$text);
           
$cnt substr_count($text$v);
           
           if(
$cnt 0)
           {
               
$open_cnt[$v] = $cnt;
               
$close_cnt[$v] = substr_count($text$tmp_close[$k]);
           }              
        }
        
/** 
Дальше уничтожаем непарные теги
Регулярка составлена так, что удаляет последний заявленный символ
Это дает возможность удалить незакрытые теги с конца текста,
не трогая закрытые.
*/     
        
foreach($open_cnt as $k => $v)
        {
                
            if(
$v $close_cnt[$k])
            {
                for(
$i 0$i $v $close_cnt[$k]; ++$i)
                    
$text preg_replace('#'$k .'(?!.*'$k .')#us'''$text);
            }
        
        }
    }             
// Обрабатываем текст        
        
$text mBwordwrap($text100);                 
        
$text htmlspecialchars($text);        
/** 
Если включен режим bb-тегов,
меняем обратно временные символы на HTML теги
*/    
    
if($replace)
    {       
        
$text str_replace($tmp_open$html_open$text);
        
$text str_replace($tmp_close$html_close$text);
        
$text str_replace($tmp_single$html_single$text);
    }        
// Сохраняем оригинальное форматирование                
        
$text str_replace('  ''&nbsp;&nbsp;'$text);    
        
$text nl2br($text);
// За ушкО на солнышкО                       
        
return $text;            
    } 
    
 
/**   
* Функция - аналог wordwrap()  для кодировки UTF-8
* @param string $str  //обрабатываеемая строка
* @param int $width     //максимальная длина слова
* @param string $break //разделитель
* @return string  
*/ 
           
    
function mBwordwrap($text$width 90$break "\n")
    {
       return 
preg_replace('#([^\s]{'$width .'})#u''$1'$break $text);
    }  
    
/////////////////////////////////////////////////////////////////////
   
    
if(!empty($_POST['ok']))    
    {     
        
$text = !empty($_POST['text']) ? $_POST['text'] : null;
        
$check createBBtags($textfalse);
        
        if(empty(
$check))
            echo 
'Нет текста';
        else         
            echo 
createBBtags($text);
    }
    
    
?>
<form action="" name="post" id="post" method="post">        
<textarea name="text" id="text" cols="40" rows="10"><?php echo htmlspecialchars($text);?></textarea><br />    
<input name="ok" type="submit" />    
</form> 


Вот теперь можно на входе обработать текст этой функцией в режиме очистки и посмотреть. Если есть полезный текст, то запостить. Если нет - послать лесом.

В общем и целом функция уже готова к применению. Но для полноценного функционала нехватает нескольких вещей. О них в следующих разделах.