使用phpBB3的基本功能

概要
这一章描述phpBB3中最重要的类和方法。数据库相关的操作在DBAL章被阐述。这章将要介绍phpBB3的核心功能。由于这些功能的使用是MOD开发的重要组成部分,请仔细阅读。

目录
    * 1 1.4.1. 页面输入
    * 1.4.2. 保留sessions
    * 1.4.3. 用户转向
    * 1.4.4. User类
    * 1.4.5. 用户输入校验
    * 1.4.6. 检查认证
    * 1.4.7. 插入帖子和私人消息
          o 7.1 例1.6.submit_post()的使用
    * 1.4.8. 构建URL,隐藏域和其他HTML
    * 1.4.9. 错误处理
    * 1.4.10. 登录
    * 1.4.11. 确认框
          o 11.1 例子1.7. 确认框例子
    * 1.4.12. 页面头和尾
    * 1.4.13. 综合应用 : 一个例子


1.4.1. 页面输入
request_var($var_name, $default, $multibyte = false, $cookie = false) 

phpBB3引入了一个新的方法来读取request数据: request_var(). 这个函数确保读入的变量类型是正确的,并且确保得到恰当的使用。所以建议用其替代$HTTP_POST_VARS和$HTTP_GET_VARS。有些情况下,如$_POST可以用来检查一个变量是否被提交,但是这样的参数不应该被直接分配给变量使用。request_var()返回的每一个字符串已经被stripslashed和htmlspecialchars过滤了。

request_var仅仅用来读取参数。使用POST/GET来检查一个变量是否存在,如:
$submit = (isset($_POST['submit']) ? true : false;


下面详细解释该函数的用法
function request_var($var_name, $default, $multibyte = false, $cookie = false)

- $var_name : 页面变量名。
- $default : 默认值,如果找不到页面变量,默认使用该值。
- $multibyte : 可选. 因为输入可能包含多非ascii码,几乎总是被使用。
- $cookie : 可选. 如果变量来自Cookie使用该参数。
- $var_name : 页面变量名。
- $default : 默认值,如果找不到页面变量,默认使用该值。
- $multibyte : 可选. 因为输入可能包含多非ascii码,几乎总是被使用。
- $cookie : 可选. 如果变量来自Cookie使用该参数。

最重要的参数是$default, 它决定该函数如何看待页面传输变量,如果$default是整数,那么结果被塑型为int. 如果是string,结果将被htmlspecialchars过滤等等。注意:如果是数组默认,那么总是空数组
// Reads the variable 'int_test'. The variable will be cast to int. If there is no such variable 0 will be returned. 
$int_test = request_var('int_test', 0);

// Reads the variable 'string_test'. The variable will be run through htmplspecialchars. If there is no such variable, then 'test' will be returned. 
$string_test = request_var('string_test', 'test');

// Reads the variable 'int_array_test'. The entries will be cast to int. If there are no such variables, then an empty array will be returned
$int_array_test = request_var('int_array_test', array(0));

// Reads the variable 'int_string_array_test'. The keys will be cast to int, the values run through htmlspecialchars. 
// If there are no such variables, then an empty array will be returned.
$int_string_array_test = request_var('int_string_array_test', array(0 => ''));
...

为了运行上面的代码,应在上面加入下面的代码,并把该文件放到phpBB根目录下运行。
$phpbb_root_path = './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
require($phpbb_root_path . 'common.' . $phpEx);

1.4.2. 保留sessions
append_sid($url, $params = false, $is_amp = true, $session_id = false)

phpBB尽量使用cookies来跟踪sessions,但是有时cookie并不总有效,有一个url重写的方案。为了让url重写方案系统工作,要求:论坛页所有链接需要append_sid函数组装。

1.4.3. 带用户会话的页面转向
meta_refresh($time, $url)

为了转向其他页面,例如在执行一个动作之后,使用meta_refresh函数。第一个参数是转向目标页面的间隔秒数,第二个参数是要转向的目标URL.记住使用append_sid转向另一个论坛页
$meta_info = append_sid("{$phpbb_root_path}api_example.$phpEx");
meta_refresh(3, $meta_info);

1.4.4.用户类
这个类是检查和修改当前用户信息的主要工具。User扩展Session类。持有当前用户的变量是$user。一个基本应用是:在页面的开始处设置用户的session
$user->session_begin();
$auth->acl($user->data);
$user->setup();
...

让我们看看经由user对象能存取哪些信息,看看user对象里有哪些数据:
  * lang 该数组持有为该用户定义的所有语言。你可以用add_lang加入更多语言或者通过setup方法的参数达成同样的目的。
  * page 当前页面位置信息。.
        o page_name 当前页名
        o page_dir 相对于phpbb_root_path的目录.
        o query_string
        o script_path
        o root_script_path
        o page 带查询字符串的页面名.
  * data 实际的用户数据和设置.
        o user_id
        o user_type
        o group_id 用户所在的默认组
        o user_ip
        o user_regdate
        o username
        o username_clean
        o user_email
        o user_email_hash
        o user_birthday
        o user_lastvisit
        o user_lastmark
        o user_lastpost_time
        o user_lastpage
        o user_last_confirm_key 安全相关
        o user_last_search
        o user_warnings
        o user_last_warning
        o user_login_attempts
        o user_inactive_reason
        o user_inactive_time
        o user_posts
        o user_lang
        o user_timezone
        o user_dateformat
        o user_style
        o user_rank
        o user_colour
        o user_message_rules
        o user_full_folder
        o user_emailtime
        o user_topic_show_days, user_topic_sortby_type, user_topic_sortby_dir, user_post_show_days, user_post_sortby_type, user_post_sortby_dir Preferences for reading
        o user_notify
        o user_notify_pm
        o user_notify_type
        o user_allow_pm
        o user_allow_viewonline
        o user_allow_viewemail
        o user_allow_massemail
        o user_options
        o user_avatar
        o user_avatar_type
        o user_avatar_width
        o user_avatar_height
        o user_sig
        o user_sig_bbcode_uid 和 user_sig_bbcode_bitfield 用来渲染签名.
        o user_from
        o user_icq
        o user_aim
        o user_yim
        o user_msnm
        o user_jabber
        o user_website
        o user_occ
        o user_interests
        o user_actkey
        o user_newpasswd
        o is_registered
        o is_bot
        o session_admin
        o session_page
  * browser 用户浏览器字符串
  * host
  * session_id
  * ip
  * time_now
  * update_session_page

看看如下两个方法:
  * setup($lang_set = false, $style = false) 这个方法被用来初始化user对象。它的参数是可选的。
  - lang_set: 加入附加的语言,可以是语言文件的名字或者名字数组
  - style : 持有style ID号.
  * add_lang($lang_set) 用来动态地加载附加的语言文件。
  - $lang_set: 可以是文件名或者文件名列表。
  第二、第三个参数从来不使用。

看看源代码session.php文档学习更多关于User类.
1.4.5. 用户输入校验
validate_data($data, $val_ary)

$data = array(
    'user_password'     => request_var('user_password', '', true),
    'password_confirm'  => request_var('password_confirm', '', true),
);

$check_ary = array(
    'user_password'     => array(
        array('string', true, $config['min_pass_chars'], $config['max_pass_chars']),
            array('password')),
    'password_confirm'  => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']),
);
functions_user.php提供一组强大的用于输入校验的函数。大部分为用户配置设计。validate_data的第一个参数持有输入参数,第二个参数持有参数校验规则,调用后入过校验失败时返回错误信息

看下面例子:
$error = validate_data($data, $check_ary);

validate_data知道下面的输入格式:

* string 字符串检查
  o optional boolean. 如果为true,空是允许的,默认为false.
  o max int. 最小长度.
  o max int. 最大长度
* num 数字检查.
  o optional boolean. 如果为true,空是允许的,默认为false.
  o max number. 最小值默认为0.
  o max number. 最大值默认为1E99
* match 检查两个值是否相等
  o optional boolean. 如果为true,空是允许的,默认为false.
  o 要匹配的其他值
* username 使用当前禁止的数据、设置和usernames
  o allowed_username 不管配置如何,指定一个允许的用户名,默认为当前登录用户名.
* email.使用当前禁止的数据、设置和email
  o allowed_email 不管配置如何,指定一个允许的用户名,默认为当前用户的email.
* match 正则表达式检查
  o optional boolean. 如果为true,空是允许的,默认为false.
  o match The Perl-Perl兼容的正则表达式。
1.4.6.认证检查
acl_get($opt, $f = 0)

为了使用认证系统,首先要设置当前用户的权限,这通过$auth对象的acl方法来实现:$auth->acl($user->data);. 该方法只有在用户的session被初始化之后才能使用.
权限被分组为几个分类里.a_开头的权限名是admin权限,u_开头是用户权限,f_开头的是论坛权限.一般来说Admin和User权限是全局的,这意味着他们能在所有的情况下使用.Moderator权限可能是本地的也可能是全局的,论坛权限总是本地的.本地的权限仅仅能用在某个论坛里。
为了检查当前用户权限,使用$auth对象的acl_get方法,它要求一个权限名字为参数,返回true或false.对于本地权限,论坛ID作为第二个参数要求传入。如果你想检查一个以上的权限,使用acl_gets方法
小提示:权限可以用'!'反转.
// checking one global permissions.
if (!$auth->acl_get('a_groups'))
...
// checking two local permissions.
if (!$auth->acl_gets('f_list', 'f_read', $forum_id))
....

1.4.7. 插入帖子和私人消息
function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags,$allow_bbcode = false, $allow_urls = false, $allow_smilies = false)
function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data,$update_message = true)
function submit_pm($mode, $subject, &$data, $put_in_outbox = true)


让我们开始为增加一个帖子或者私人消息准备数据——这个数据应该能允许BBCODES.phpBB3提供了一个函数:
generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false).
define('IN_PHPBB', true);
$phpbb_root_path = '../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
require_once($phpbb_root_path . 'common.' . $phpEx);
require_once($phpbb_root_path . 'includes/functions_content.' . $phpEx);
// note that multibyte support is enabled here 
$my_text = utf8_normalize_nfc(request_var('text', '', true));               
// variables to hold the parameters for submit_post
$uid = $bitfield = $options = '';                  
generate_text_for_storage($my_text, $uid, $bitfield, $options, true, true, true);
echo $my_text;
// save $my_text into database.

提示:还有一个generate_text_for_display函数,生成用于显示的HTML
这里我们忽略"投票"和"附件",phpBB3提供了强大的方法添加帖子和私人信息,这里我只覆盖他的基本特性。
submit_post用来新增一条贴子:
submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true).
- $mode : 使用'post'
- $topic_type : 参考主题类型(sticky等,描述在constants.php).
- &$poll : 我们不覆盖投票,设置为false.
- $data : $data是数组,包含post的参数,大部分参数很简单,但斯几个参数需要用前面提及的generate_text_for_storage方法.使用下面的参数足够插入一条消息(实际有更多参数):

    * forum_id int. 论坛ID. 对于全局公告该参数设为空,否则设置为要发布的论坛版面ID.
    * icon_id 要显示的图标.
    * enable_bbcode boolean.
    * enable_urls boolean.
    * enable_sig boolean.
    * message 需要generate_text_for_storage方法提供
    * message_md5 使用md5() 在运行message的generate_text_for_storage来获得md5($my_message)
    * bbcode_bitfield 用于generate_text_for_storage的bitfield
    * bbcode_uid string. 用于generate_text_for_storage的uid
    * post_edit_locked int
    * enable_sig boolean
    * topic_time_limit
    * post_edit_locked int, 常量ITEM_LOCKED/ITEM_UNLOCKED
    * topic_title String
    * notify_set boolean
    * notify boolean
    * post_time int. 现在使用'0'
    * forum_name String. 仅仅用于email通知
    * enable_indexing boolean.
提示:submit_post函数总是使用当前用户对象作为poster
// note that multibyte support is enabled here 
$my_subject = utf8_normalize_nfc(request_var('my_subject', '', true));
$my_text    = utf8_normalize_nfc(request_var('my_text', '', true));

// variables to hold the parameters for submit_post
$poll = $uid = $bitfield = $options = ''; 

generate_text_for_storage($my_subject, $uid, $bitfield, $options, false, false, false);
generate_text_for_storage($my_text, $uid, $bitfield, $options, true, true, true);

$data = array( 
    'forum_id'      => 2,
    'icon_id'       => false,

    'enable_bbcode'     => true,
    'enable_smilies'    => true,
    'enable_urls'       => true,
    'enable_sig'        => true,

    'message'       => $my_text,
    'message_md5'   => md5($my_text),
                
    'bbcode_bitfield'   => $bitfield,
    'bbcode_uid'        => $uid,

    'post_edit_locked'  => 0,
    'topic_title'       => $my_subject,
    'notify_set'        => false,
    'notify'            => false,
    'post_time'         => 0,
    'forum_name'        => '',
    'enable_indexing'   => true,
);

submit_post('post', $my_subject, '', POST_NORMAL, $poll, $data);

发送私人消息的函数submit_pm和submit_post很类似
function submit_pm($mode, $subject, &$data, $put_in_outbox = true). $mode参数为'post',$data参数解释如下:
    * address_list 数组.
    收条列表,是一个嵌套数组结构如下:
    array ('u' => array(2 => 'to' 3 => ' bcc'), ('g' => array(2 => 'to' 3 => ' bcc'))) 'u'是用户,'g'是组.
    * from_user_id int.发送人用户ID
    * from_user_name. 发送人.
    * icon_id.要使用的图标 The icon to use.
    * from_user_ip.
    * enable_bbcode boolean.
    * enable_smilies boolean.
    * enable_urls boolean.
    * enable_sig boolean.
    * message.需要generate_text_for_storage方法获得这个值
    * bbcode_bitfield. 用message_parser获得这个值
    * bbcode_uid. 用message_parser获得这个值
// note that multibyte support is enabled here 
$my_subject = utf8_normalize_nfc(request_var('my_subject', '', true));
$my_text    = utf8_normalize_nfc(request_var('my_text', '', true));

// variables to hold the parameters for submit_pm
$poll = $uid = $bitfield = $options = ''; 
generate_text_for_storage($my_subject, $uid, $bitfield, $options, false, false, false);
generate_text_for_storage($my_text, $uid, $bitfield, $options, true, true, true);

$data = array( 
    'address_list'      => array ('u' => array(2 => 'to')),
    'from_user_id'      => 2,
    'from_username'     => 'test',
    'icon_id'           => 0,
    'from_user_ip'      => $user->data['user_ip'],
     
    'enable_bbcode'     => true,
    'enable_smilies'    => true,
    'enable_urls'       => true,
    'enable_sig'        => true,

    'message'           => $my_text,
    'bbcode_bitfield'   => $bitfield,
    'bbcode_uid'        => $uid,
);

submit_pm('post', $my_subject, $data, false);

小提示:为了使用submit_post,需要包含functions_posting.php,同理,为了使用submit_pm ,需要包含functions_privmsgs.php

1.4.8. 构建URL,隐藏域和其他HTML
build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false)
build_url()

phpBB3 offers a few functions to take care of the dirty deed of untemplated HTML. The important entries in the category are build_hidden_fields and build_url. Neither is doing anything unexpected, but here we go: build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false). The function will use the entries of the first parameter (array, name value) to build a string of hidden HTML input fields. That string is returned as result. If the second parameter is set to true, the function will use htmlspecialchars on the keys and the values in the first parameter; if the third is true it will use stripslashes. See Example 1.7, “Example confirm box”

build_url is even simpler: it will generate a valid url to the current page in the forum and return it as string. You can pass an array of GET parameter names which should be stripped from the url as argument.

1.4.9. 错误处理
严格来说,这不是phpBB代码部分,但是它替代了phpBB2的message_die方法,所以这里加以介绍,非常简单: 错误信息作为trigger_error参数调用即可,下面的例子是用多语言特性;
trigger_error($user->lang['SOME_LANG_KEY']);

对于权限的违反,你可以使用"E_USER_WARNING"常量:
trigger_error($user->lang['NOT_MANAGE_FOUNDER'] . adm_back_link($this->u_action), E_USER_WARNING); 

1.4.10.登 录
login_box($redirect = , $l_explain = , $l_success = , $admin = false, $s_display = true)


登录提示可以由login_box函数产生.
- $redirect : indicates the page where the user should be redirected to after a successful login;
- $l_explain: contains the text which should be shown as explanation
- $l_success: should contain the text to display in the case of a successful login.

小提示:如果$redirect为空将转向原来的页,实际上该函数可以不需要任何参数。
if ($user->data['user_id'] == ANONYMOUS || $user->data['is_bot'])
{
    login_box('', $user->lang['SOME_LANG_KEY']);
}

1.4.11.确认页
confirm_box($check, $title = , $hidden = , $html_body = 'confirm_body.html',$u_action = )
if ($submit)
{
    // check mode
    if (confirm_box(true))
    {
        submit($my_message);
    }
    else
    {
        $s_hidden_fields = build_hidden_fields(array(
            'submit'    => true,
            'my_mesage' => $my_message,
            )
        );

        //display mode
        confirm_box(false, 'SAMPLE_LANG_KEY', $s_hidden_fields);
    }


1.4.12.页面头和脚
page_header()
page_footer()
make_jumpbox($action)


1.4.13.综合应用:一个例子
三个文件:
$PHPBB_HOME/api_example.php
$PHPBB_HOME/styles/$TEMPATE_NAME/template/api_example.html
$PHPBB_HOME/language/$CURRENT_LANG/mods/api_example.php

api_example.php
<?php
/** 
*
* @package phpBB3
* @version $Id: v3_api.xml 52 2007-12-09 19:45:45Z jelly_doughnut $
* @copyright (c) 2007 phpBB Group 
* @license http://opensource.org/licenses/gpl-license.php GNU Public License 
*
*/


// The default phpBB inclusion protection - required
define('IN_PHPBB', true);
$phpbb_root_path = './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);


include($phpbb_root_path . 'common.' . $phpEx);
include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);


// Start session management
$user->session_begin();
$auth->acl($user->data);
// our lang file is in the mods directory
$user->setup(array('memberlist', 'mods/api_example'));


$page_title =  $user->lang['SEND_PM_SELF'];

// Read user input
$my_subject     = request_var('my_subject', '', true);
$my_message     = request_var('my_message', '', true);

$my_subject     = utf8_normalize_nfc($my_subject);
$my_message     = utf8_normalize_nfc($my_message);

$submit = (isset($_POST['submit'])) ? true : false;

// check permissions
if (!$auth->acl_gets('u_sendpm', 'u_readpm'))
{
    if ($user->data['is_registered'])
    {
        trigger_error('EXAMPLE_SEND_PM_DENIED');
    }

    login_box('', $user->lang['EXAMPLE_SEND_PM_LOGIN']);
}


if ($submit)
{
    if (confirm_box(true))
    {
        // variables to hold the parameters for submit_pm
        $poll = $uid = $bitfield = $options = ''; 
        generate_text_for_storage($my_subject, $uid, $bitfield, $options, false, false, false);
        generate_text_for_storage($my_text, $uid, $bitfield, $options, true, true, true);

        $data = array( 
            'address_list'      => array ('u' => array($user->data['user_id'] => 'to')),
            'from_user_id'      => $user->data['user_id'],
            'from_username'     => $user->data['username'],
            'icon_id'           => 0,
            'from_user_ip'      => $user->data['user_ip'],
             
            'enable_bbcode'     => true,
            'enable_smilies'    => true,
            'enable_urls'       => true,
            'enable_sig'        => true,
                    
            'message'           => $my_message,
            'bbcode_bitfield'   => $bitfield,
            'bbcode_uid'        => $uid,
        );
        submit_pm('post', $my_subject, $data, true);
        
        $meta_info = append_sid("{$phpbb_root_path}api_example.$phpEx");
        $message = $user->lang['EXAMPLE_PM_SENT'] . '<br /><br />' . sprintf($user->lang['RETURN_SEND_PM'], '<a href="' . $meta_info . '">', '</a>');
        meta_refresh(3, $meta_info);
        trigger_error($message);
    }
    else
    {
        $s_hidden_fields = build_hidden_fields(array(
            'submit'        => true,
            'my_message'    => $my_message,
            'my_subject'    => $my_subject,
            )
        );
        
        // display mode
        confirm_box(false, $user->lang['EXAMPLE_API_REALLY'], $s_hidden_fields);
    }
}

// Output the page
page_header($page_title);

$template->assign_vars(array(
    'S_MY_MESSAGE'  => $my_message,
    'S_MY_SUBJECT'  => $my_subject,
    'S_SEND_ACTION' => build_url('confirm_key'),
    )
);

$template->set_filenames(array(
    'body' => 'api_example.html')
);

make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));

page_footer();

?>

api_example.html
<!-- INCLUDE overall_header.html -->

<div id="pagecontent">

    <form name="send" action="{S_SEND_ACTION}" method="post">
    
        <table class="tablebg" width="100%" cellspacing="1">
            <tr>
                <th>{L_SEND_TITLE}</th>
            </tr>
            <tr>
            <td class="row3" align="center"><span class="genmed">{L_SEND_EXPLAIN}</span></td>
            </tr>
            <tr>
                <th>{L_SEND_SUBJECT}</th>
            </tr>
            <tr>
                <td class="row1" align="center"><input name="my_subject" value="{S_MY_SUBJECT}" size="76" /></td>
            </tr>
            <tr>
                <th>{L_SEND_MESSAGE}</th>
            </tr>
            <tr>
                <td class="row2" align="center"><textarea name="my_message" rows="10" cols="76">{S_MY_MESSAGE}</textarea></td>
            </tr>
            
            <tr>
                <td class="cat" align="center"><input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />
                &nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" /></td>
            </tr>
        </table>
    </form>
    
</div>
<br clear="all" />

<!-- INCLUDE breadcrumbs.html -->

<br clear="all" />

<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>

<!-- INCLUDE overall_footer.html -->

api_example.php
<?php
/** 
*
* example [English]
*
* @package language
* @version $Id: v3_api.xml 52 2007-12-09 19:45:45Z jelly_doughnut $
* @copyright (c) 2007 phpBB Group 
* @license http://opensource.org/licenses/gpl-license.php GNU Public License 
*
*/

/**
* DO NOT CHANGE
*/
if (empty($lang) || !is_array($lang))
{
    $lang = array();
}

// DEVELOPERS PLEASE NOTE
//
// All language files should use UTF-8 as their encoding and the files must not contain a BOM.
//
// Placeholders can now contain order information, e.g. instead of
// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows
// translators to re-order the output of data while ensuring it remains correct
//
// You do not need this where single placeholders are used, e.g. 'Message %d' is fine
// equally where a string contains only two placeholders which are used to wrap text
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine

$lang = array_merge($lang, array(
    'SEND_TITLE'                => 'Send a PM to yourself',
    'SEND_EXPLAIN'              => 'Just a little example. You can use it to send PMs to yourself. Fun!',
    'SEND_SUBJECT'              => 'Subject',
    'SEND_MESSAGE'              => 'Message',
    'EXAMPLE_API_REALLY'        => 'Do you really want to send a PM to yourself?',
    'EXAMPLE_PM_SENT'           => 'You have sent a PM to yourself. You have no life.',
    'RETURN_SEND_PM'            => 'That was fun. Let\'s do it %sagain%s.',

 
    'EXAMPLE_SEND_PM_LOGIN'         => 'Login to send a PM to yourself',
    'EXAMPLE_SEND_PM_LOGIN_SUCC'    => 'Send a PM',
    'EXAMPLE_SEND_PM_DENIED'        => 'You are not allowed to send yourself PMs',
    'SEND_PM_SELF'                  => 'Send a PM to yourself',
));

?>

你可能感兴趣的:(html,PHP,正则表达式,公告,OpenSource)